讨论java两个奇怪的语法现象

olivesoup 2007-12-13 01:41:29
加精
1.为什么方法里只要有while循环就可以不用返回值,而且必须是while,for循环就不行

private String abc(){
while(true){
}
}


2.jdk1.5开始增加了范型,为什么数组不支持范型,数组的范型检查警告该如何消除(请别说用@SuppressWarnings("unchecked"))
 
List[] listArray = new List[]{new ArrayList<String>(), new ArrayList<String>()};
listArray[0].add("0");
listArray[1].add("1");
...全文
2054 39 打赏 收藏 转发到动态 举报
写回复
用AI写文章
39 条回复
切换为时间正序
请发表友善的回复…
发表回复
jayjayjaymin 2008-10-08
  • 打赏
  • 举报
回复
    public static String abc(){
final boolean b = getB();

while(b){

}
}

private static boolean getB(){
return true;
}

此段代码无法造成次循环 b还是不能确定的 为什么呢?
shadowing_fly 2008-05-03
  • 打赏
  • 举报
回复
[Quote=引用 28 楼 olivesoup 的回复:]
楼上回答的第二个问题是用向下转型消除了警告,表面上似乎是解决了,
但如果我把写法改一下你又该如何转型呢?

Java code
ArrayList[] listArray = new ArrayList[]{new ArrayList<String>(), new ArrayList<String>()};
[/Quote]

自己再继承arraylist再转呗........
qqxierh 2008-05-01
  • 打赏
  • 举报
回复
受益不浅
ccbianshen 2008-04-30
  • 打赏
  • 举报
回复
[Quote=引用 35 楼 kevinchj 的回复:]
虽然,结贴了,但是学习……
受益匪浅……
[/Quote]
kevinchj 2008-04-17
  • 打赏
  • 举报
回复
虽然,结贴了,但是学习……
受益匪浅……
kimmking 2008-04-16
  • 打赏
  • 举报
回复
很多技术文章中提到了 oop和泛型中间有很多设计原则上的冲突。
nihuajie05 2008-03-27
  • 打赏
  • 举报
回复
啥叫范性????
yongaolee 2008-03-26
  • 打赏
  • 举报
回复
不太懂``
qixujuan 2008-03-26
  • 打赏
  • 举报
回复
hehe
Ivony 2008-03-25
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 bao110908 的回复:]
但是,如果按照4楼所说的,下面的代码怎么解释呢?

这样会报错的,也是个死循环。


Java codepublic static String abc(){
boolean b = true;
while(b){

}
}
[/Quote]


这个根本就没有办法保证是死循环。
olivesoup 2007-12-17
  • 打赏
  • 举报
回复
楼上回答的第二个问题是用向下转型消除了警告,表面上似乎是解决了,
但如果我把写法改一下你又该如何转型呢?

ArrayList[] listArray = new ArrayList[]{new ArrayList<String>(), new ArrayList<String>()};
Dan1980 2007-12-17
  • 打赏
  • 举报
回复
呵呵,关于第二个问题,读了一下sun的官方文档,发现泛型的限制还是蛮多的。

泛型只是一个编译时范畴,编译器在编译期间会对所有的泛型声明执行类型消除(Type Erasure ),也就是说,任何和运行时相关的操作都不支持泛型。只有编译器认识泛型,JVM根本不认识。所以泛型机制只是编译器方面的革新,泛型机制编译出来的字节码,并不需要一个所谓“支持泛型的JVM”来解释。
数组的类型是需要在编译时确定的,所以,创建“泛型数组”就意味着要编译器把这个泛型对象留给JVM去解释,违背了“类型消除”的原则。所以,“泛型数组”是不存在的。
Dan1980 2007-12-14
  • 打赏
  • 举报
回复
第二个问题,改成下面这样就可以不出现安全警告了:

List[] listArray = new List[]{new ArrayList<String>(), new ArrayList<String>()};
((ArrayList<String>)listArray[0]).add("0");
((ArrayList<String>)listArray[1]).add("1");
olivesoup 2007-12-14
  • 打赏
  • 举报
回复
关于第二个问题,研究了一下Collection下的class,竟发现有无数的安全警告,
看来这个问题连编写jdk的sun的技术者也无法解决,只能先这么摆着了。

另外感谢angues1980石头心提供的资料,很实用的!并且期待你对虚拟机的研究成果。
Dan1980 2007-12-14
  • 打赏
  • 举报
回复
楼主好学的精神值得大家学习哦!

第一个问题其实是基于一条简单的规则:JAVA不允许有编译器能确定的永远执行不到的语句(即使是return语句也不行!)。
所以,这个问题不是“可以不返回值”,而是“不能返回”,也就是说,在死循环后面加上返回是错的,因为这里的返回语句是永远执行不到的。

语句永远不被执行的情况有几种:出现在明确的死循环之后,出现在明确的return语句之后,出现在明确的异常抛出语句之后。
这里的“明确的”意思是编译器可以确定的,基于这个规则,下面的代码都不能编译:

int f() {
return 0;
System.out.println("never reach here!"); // won't compile!
}

int g() {
while(true); // or equally, for(;;) ;
return 0; // won't compile!
}

int h() {
throw new RuntimeException();
return 0; // won't compile!
}

但是,编译器毕竟不是完全智能的,很多可以“明确”的情况下,它也可能置之不理。如if(true)后面的return语句和throw语句,有变量参与的死循环等等。

编译器的职责是检查语法错误,而不是语义错误,JAVA编译器管得比较宽,但依赖编译器来检查语义错误总是不可取的。
angues1980 2007-12-14
  • 打赏
  • 举报
回复
TO:18楼

你试试用javac自己编译一下,看看会不会报错。
怎么能说“这个不是Java语法的问题”呢?
angues1980 2007-12-14
  • 打赏
  • 举报
回复
嗯,我的猜测有点问题,有可能像楼主说的那样

正在看《深入Java虚拟机》,估计这样设计也是和虚拟机一样为了避免“停机问题”吧
迷眼流金 2007-12-14
  • 打赏
  • 举报
回复
因为你while(true)的时候,ide认为代码到这里就会看不到while下面的(没机会运行)所以也就不需要检查最终的返回
你可以尝试 while(false) 看看ide会不会报错-- 这个不是java语法的问题
olivesoup 2007-12-14
  • 打赏
  • 举报
回复
15楼的说法似乎解释不通,将火龙果的代码做些修改就能通过了

public static String abc(){
final boolean b = true;
while(b){

}
}

虽然都是使用了b,但是编译器判断出不加final的b有可能被改变,所以是否形成死循环是不确定的,
而加了final的b已经确定会造成死循环。

将代码再做些修改

private static final boolean B = true;

public static String abc(){
final boolean b = B;

while(b){

}
}

同样证明了刚才的说法,将B的final去掉,或不进行初始化,B就会具有不确定性,无法造成死循环,因此出错

将代码再做些修改

public static String abc(){
final boolean b = getB();

while(b){

}
}

private static boolean getB(){
return true;
}

b由方法getB取得,getB是私有的,显然具有唯一性,返回的也是确定的true,那么按理b也应该是确定的,
但遗憾的是编译器告诉我们abc需要返回值,也就是他判断的结果是b是不确定的,不知道是true还是false.

我们再做些改变

public static String abc() {
final boolean b = ClassB.BB;

while (b) {

}
}

private class ClassB {
private static final boolean BB = true;
}

这回b的值由ClassB的常量BB提供,编译通过了,将BB的final去掉或是不进行初始化都无法通过。
看来编译器只能判断到常量字段,到了方法这一级别它就会认为具有不确定性。


maquan 2007-12-14
  • 打赏
  • 举报
回复
回答 10 楼的问题:

我认为应该是这样的:编译器能够静态识别出所有的 reachable branch。而你那段程序,并不能在编译期就判定为“死循环”,所以就报错了。

我估计,如果你把 b 的定义改成 final boolean b = true; 应该就能编译通过了。我没试过,猜的 :)
加载更多回复(18)

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧