首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > JAVA > J2SE开发 >

您不知道的java(SE)

2013-09-05 
你不知道的java(SE)(这个标题很有种似曾相识的感觉吧?嘿嘿。)知其然,知其所以然。我们学习、使用java,刚开始

你不知道的java(SE)
(这个标题很有种似曾相识的感觉吧?嘿嘿。)

知其然,知其所以然。我们学习、使用java,刚开始一些细节的东西可能会困扰我们,时间久了,往往会觉得理所当然,问题还是不太清楚。被人问起的时候,可能会“理所当然”的告诉别人,“这是java封装了的,知道怎么用就行啦”。长此以往,我们可能会的工具或配置很多,却无所长进。

为了一定程度上辅助我们搞清楚这种模糊的概念、细节,特此在java大版各个子板,开通一个《你不知道的java》系列帖子,希望汇聚众“Java人”的经验和汗水,发扬“开源”的思想,使我们知道一些java的细节、工具或配置文件的处理流程,成为多懂一些Java的人。

规则:
1. 留言的同学,先抛出自己发现的,别人可能不知道的细节问题,再给出这个问题的答案。
2. 围观的同学,如果觉得有哪些细节让你为之叫好,请您点一下“对我有用”。
3. 每月结贴一次,根据“对我有用”的程度和问题精彩程度,奖励相应比例积分。(俺的权限就200分,要是僧多粥少了,希望众大大别怪俺小气哈!)

你不知道的java(SE)
这里先厚颜扔两块板砖:
1. 执行java程序,如何给main方法传参?
命令行执行的时候,在类名后跟参数,以空格分隔多个参数,例如:
java MyTest Tomcat is good in use.
"Tomcat is good in use."会分成五个字符串,传递给MyTest的main方法(作为args)。

2. 我们平时使用的String、Integer等j2se基本类,在java安装环境什么地方?
在$HOME\jre\lib\rt.jar中。(rt,无处不在啊。。)

3. 打的jar包没问题,MANIFEST.MF也设置了Main-Class,为何还是无法执行响应的main方法(报错“Invalid or corrupt jarfile”)?
Main-Class: 冒号后面要加空格,再配置上带上包路径的类,例如:
Main-Class: com.test.HelloWorld
这样就可以在命令行里执行jar包:java -jar XXX.jar
(当然,如果配置了jar文件的默认打开方式为“Java(TM) platform SE binary”,也可以双击jar文件执行)

4. 都说字符串hashCode相同,不一定equals,如何构造俩字符串,使其hashCode相同,字符串不同?
首先,为了简化问题,我们可以限定,长度同为两位的字符串。
我们知道String.hashCode方法的哈希策略(参考源码):循环遍历字符串中的字符(c表示字符,ASCc表示c的ASCII值),计算:hashcode = 31*hashcode+ASCc
因为字符串只有两位,hashcode初始值为0,我们的两个字符串假设为"XY"与"MN",则其hashcode分别为(31*ASCX+ASCY)和(31*ASCM+ASCN)。
接下来凑数就可以了:ASCX和ASCM可以取任意值(尽量小些,在ASCII码范围内),ASCY和ASCN要根据ASCX和ASCM的取值,得到曲线关系(取值也要在ASCII码范围0~127内凑)。
比如ASCX取值49,ASCM取值50,则得到等式:31*49+ASCY=31*50+ASCN ,转换:ASCY=31+ASCN。此时,不妨ASCN取值66,则ASCY取值97。
接下来大家可以用System.out.println((char)49);方式得知各ASCII码对应的字符:49,'1';  50,'2';  66,'B';  97,'a'。
于是乎,hashCode相同,字符串不同的两个字符串构造好了:"1a","2B"(我擦,不是故意构造这个字符串的。。)。
(这里为了好看,凑了个常规字符,大家也可以试试其他ASCII码字符,0~127范围内的哦)

不积跬步无以至千里,不积小流无以成江海。

题外话:
因个人能力有限,先在J2SE版试行,欢迎对java其他版块有经验的同学,以同样的标题发个话题。
如果分数有限的话,也可以给我留言,我来汇总发帖(并标注问题提供者的ID)。
欢迎大家提出改进意见。
[解决办法]
jdk7中switch表达式可以是String。这算不算
[解决办法]
我们打印字符串的时候一直只知道有System.out.print和System.out.println两个函数,我也是最近才知道,原来java还有提供类似c语言的printf函数。




[解决办法]
String 对象不可变,相加时先转化为StringBuffer,调用append方法,最后再转化为String,原先的String再引用它
[解决办法]
类成员变量加载顺序为:父类静态块(静态变量) --> 然后是子类静态块(静态变量) --> 父类成员变量 --> 父类构造函数块 --> 子类成员变量 --> 子类构造函数块
[解决办法]
静态方法调用的限定表达式是可以计算的,但是它的值将被忽略。无非空限制
System.out.println(((Math) null).random());

[解决办法]
可变参数的应用(C,CPP都有这种语法,最典型的就是字符串format的实现):
public PrintWriter format(String format, Object ... args);
[解决办法]
引用:
String 对象不可变,相加时先转化为StringBuffer,调用append方法,最后再转化为String,原先的String再引用:
Quote: 引用:

String 对象不可变,相加时先转化为StringBuffer,调用append方法,最后再转化为String,原先的String再引用它

其实如果是少量字符串的拼接操作,可以使用+操作。如果拼接比较频繁,就可以按照你的讲法来实现了。

现在使用StringBuilder。 + 操作会被编译器转成 StringBuilder的append
[解决办法]
引用:
请问,这种操作符的内部处理,有没有相关的博文或者书籍呀?

String 的 + 操作,写段代码,编译后,用 javap -c 查看。
------解决方案--------------------


我们一般在编写java代码的时候,一般都是用英文字母、下划线、数字等作为类名、变量名等,但是实际上java完全可以支持使用中文作为这些名称。
如下代码,也是可以运行的。



public class 测试 {
public static void main(String[] args) {
String 姓名="张三";
int 年龄=30;
System.out.printf("姓名:%s,年龄:%d",姓名,年龄);
}
}


[解决办法]
引用:
C: 你性能没我高


c的性能比java高,那得看是做什么类型的应用。

现在java的性能已经不是问题了,虽然说理论上肯定没有c的性能高,但是在有些应用,如web,java的性能会表现的非常高,因为用c来开发这种应用,会消耗大量的开发成本且不一定效率就比java高多少,用c稍微处理不好的话(不是所有的程序员都能保证程序中没有失误)还不如java。

另外把用java开发降低成本的钱多买台服务器,做个集群,比c写的性能肯定更好。
[解决办法]
引用:
静态方法调用的限定表达式是可以计算的,但是它的值将被忽略。无非空限制
System.out.println(((Math) null).random());


静态方法绑定会绕过对具体 reference 的检查,这个以前真不知道。
专门去查了 JLS 7 编译时方法绑定的部分,于是有了下面的代码,猜猜看能不能编译,如果能,这些方法调用都输出什么:


public class MethodDeterminationTest {
  
  public static void main(String[] args) {
    
    Object o = "abc";
    
    MethodDeterminationTest.print(o);
    
    MethodDeterminationTest.<String>print("abcd");
    
    MethodDeterminationTest.<Integer>print(5);
    
    MethodDeterminationTest.<Integer>print("abcd");
    
    ((MethodDeterminationTest)null).<Number>print(5.0);
  }
  
  public static <E> void print(E e) {
    
    System.out.println("generic " + e);
  }
  
  public static void print(String s) {
    
    System.out.println(s);
  }
}


其实知道这些大概也很少用到,不过可能极少数的情况当你debug别人糟糕至极的overloading代码的时候,知道这些脑子里至少会有一根警惕的弦。
[解决办法]
引用:
Quote: 引用:

静态方法调用的限定表达式是可以计算的,但是它的值将被忽略。无非空限制
System.out.println(((Math) null).random());


静态方法绑定会绕过对具体 reference 的检查,这个以前真不知道。
专门去查了 JLS 7 编译时方法绑定的部分,于是有了下面的代码,猜猜看能不能编译,如果能,这些方法调用都输出什么:


public class MethodDeterminationTest {
  
  public static void main(String[] args) {
    
    Object o = "abc";
    
    MethodDeterminationTest.print(o);
    
    MethodDeterminationTest.<String>print("abcd");
    
    MethodDeterminationTest.<Integer>print(5);
    
    MethodDeterminationTest.<Integer>print("abcd");
    
    ((MethodDeterminationTest)null).<Number>print(5.0);
  }
  
  public static <E> void print(E e) {
    
    System.out.println("generic " + e);
  }
  
  public static void print(String s) {
    
    System.out.println(s);
  }
}


其实知道这些大概也很少用到,不过可能极少数的情况当你debug别人糟糕至极的overloading代码的时候,知道这些脑子里至少会有一根警惕的弦。


加两条:


    MethodDeterminationTest.print(null);
    
    MethodDeterminationTest.<Integer>print(null);

[解决办法]

int i=0;
i=i++;
System.out.println(i);

输出结果为0;后自增原理:首先声明一个临时变量存储i未自增的值  int temp=i; 即此时 temp=0
然后i自增加1, i=i+1;  最后返回temp, 即return temp;
也就是说 在最后执行到i=i++; 的时候  因为++的运算符优先级 高于=, 所以 i会等于 i++;  的返回值,即 i=temp=0;.....在这段程序i的变化时 i...>0.....>1.....>0
[解决办法]
许多人时间转换时,自己乘一串数字,其实 java.util.concurrent.TimeUnit 提供了转换方法:

如 5天是多少秒 TimeUnit.DAYS.toSeconds(5l); 不必 60l × 60 × 24 × 5
[解决办法]
 null instanceof Xxxx 返回 false
所以 
 aObject != null && aObject instanceof Xxxx 前面的非null判断是多余的。

=============================================

Collections.<String,Integer>emptyMap()


=============================================
public class Baz<T extends Foo & Bar> {}

==============================================
List<Integer> numbers = new ArrayList<Integer>(){{ add(1); add(2); }};

Map<String,String> codes = new HashMap<String,String>(){{ 
  put("1","one"); 
  put("2","two");
}};


[解决办法]

引用:
说一个可能大家都知道的:java最大的特性是与平台的无关性,因为java是运行在java虚拟机上,即jvm(Java Virtual Machine),它是通过在实际计算机上仿真模拟各种计算机功能来实现的。它负责与操作系统交互,用来屏蔽操作系统环境,供java运行,使得Java程序只需生成能在Java虚拟机上运行的字节码即可。

补充一点,java语言和java虚拟机将来会是两个方向独立发展,因为java虚拟机可以运行字节码文件,而字节码文件不一定只能由java语言生成,事实上,现在已经有一些语言,可以生成字节码,运行于Java虚拟机,如JRuby,Groovy等,期待jvm未来更通用。
[解决办法]
java四舍五入问题
  double a = 2.5555;
  BigDecimal b = new BigDecimal(a);
  double aa = b.setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue();
  System.out.println(aa);
  注意:因为小数a本身就在计算机中存储不精确,所有输出结果是2.555;如果要避免这种问题BigDecimal b = new BigDecimal(a);括号的要传入字符串类型即用构造方法Bigdecimal(String s).
[解决办法]
在定义enum类的方法中使用 switch(this)
[解决办法]
没有main函数的Java程序也可以通过java命令运行起来
[解决办法]
说一个大家可能都知道的:
不使用中间变量实现两个数互换
int A=3;
int B=5;
System.out.println("A="+A+"\tB="+B);
A=A^B;
B=B^A;
A=A^B;
System.out.println("A="+A+"\tB="+B);

[解决办法]
要计算某个数乘以2的n次方不必再使用for循环实现了,可以这样:

int i=3;
int j=64;
System.out.println(i<<4);//3乘以2的4次方,48
System.out.println(j>>4);//64除以2的4次方,4

这种方法有局限性,只针对底数是2
(大家可能都见过,就见笑了,呵呵)
[解决办法]
引用:
要是有个例子就好啦~


静态代码段。

【代码】
public class DontHaveMain {
    static {
        System.out.println("I'm done.");
    }
}


【测试】(在Eclipse中Run恐怕是不行滴。。。)
C:\>java DontHaveMain


I'm done.
Exception in thread "main" java.lang.NoSuchMethodError: main
[解决办法]
今天要结贴了么,想到几条说一下吧,可能有不知道的:


Calendar 不是线程安全的(这个很明显)

SimpleDateFormat 也不是线程安全的(这个也许很多人没注意过)
所以有时要避免用 private static final DateFormat SHARED = new SimpleDateFormat("..."); 这种,

—— 那能不能用 ThreadLocal 呢?
—— ThreadLocal 未必比每次新建一个 SimpleDateFormat 更高效
同理,一些建立起来很便宜的对象,比如 StringBuilder,用 ThreadLocal 都未必有效率上的优势。
Calendar 实例化稍贵,适合不适合用 ThreadLocal 呢? —— 可以自己试验。

===============

下面这些常用类都不是 immutable 的(设计缺陷?)
java.awt.Dimension
java.awt.Point
(而 java.awt.Color 却是 immutable 的,真是随机的设计啊)
java.util.Date (这个必须是设计缺陷)

而下面这些常用类是 immutable:
String
Integer, Boolean, Long, Double ... ...
BigInteger
BigDecimal

===============

EnumSet 与 EnumMap,当其所用的 enum 内元素的总个数大于64时,和小于等于64时,分别是两种不同(效率)的底层实现,小于等于64时效率更高(EnumSet在64个以内时就是一个long)

===============

对成员来说,final 包含 volatile 效果;
对方法来说,private 包含 final 效果。

===============

Arrays.sort 在排序引用类型时内部实现是  merge sort,递归到足够小的部分时内部使用 insertion sort。


[解决办法]
文件路径,可以统一使用 "/",而不必用反斜杠,java会根据OS自动转换。

===============

super.method() 是(不会被override的)安全调用,相当于调用 final 的方法,所以在构造方法中调用父类方法时,好习惯是一律加上 super.

热点排行