哈哈我其实没有想到这个系列真会有续集,上次写完01以后以为不会再写下去了,没想到最近牛客网刷题有些题目还是挺纠结的,这里补一补
构造器能带哪些修饰符
题目:
Which of the following can be applied to constructors:
A. final
B. static
C. synchronized
D. native
E. None of these.
正确答案: E 你的答案: C (错误)
我选的时候觉得A C有可能,然后因为是单选选了C。
经测试,类构造器不能带以上任何一个修饰符,如果要声明为最终类,直接在类上修饰为final的就行了。
而synchronized,我一开始以为因为方法上的synchronized
默认锁住的是this对象,而还没构造的对象可能不能锁,但后来发现并不是这个原因,起码下面这段代码是能运行的:
public class TestConstructor {
String name;
public TestConstructor(){
synchronized (this){
name = "1";
}
}
public static void main(String[] args) {
TestConstructor testConstructor = new TestConstructor();
System.out.println(testConstructor.name);
}
}
并且通过调试发现在进入synchronized
代码块之前对象已经创建出来,只是还没有对name赋值。所以可能就是硬不可以吧。
关于整数和字符串相加的问题
题目:
如果int x=20, y=5,则语句System.out.println(x+y +""+(x+y)+y); 的输出结果是()
A. 2530
B. 55
C. 2052055
D. 25255
正确答案: D 你的答案: D (正确)
这道题虽然选对了,但是是根据排除法做出来的,因为空字符串后面那部分(x+y)+y
必是255
,但是空字符串前面的那个x+y
我不确定是25
还是205
。
经测试,运行结果是25255,那就说明在遇到字符串之前还是做正常的整数加法,而遇到字符串之后都是做字符串拼接。如果思考一下原因,也很好解释,大概就是因为加法是单步执行的(JVM字节码执行的时候一条指令最多操作两个操作数栈中的操作数),那么遇到字符串之前,都不知道后面会有字符串,也就会做正常的整数加法了。
重载静态多分派
题目:
public class Demo {
public static void main(String[] args) {
Collection<?>[] collections =
{new HashSet<String>(), new ArrayList<String>(), new HashMap<String, String>().values()};
Super subToSuper = new Sub();
for (Collection<?> collection : collections) {
System.out.println(subToSuper.getType(collection));
}
}
abstract static class Super {
public static String getType(Collection<?> collection) {
return "Super:collection";
}
public static String getType(List<?> list) {
return "Super:list";
}
public String getType(ArrayList<?> list) {
return "Super:arrayList";
}
public static String getType(Set<?> set) {
return "Super:set";
}
public String getType(HashSet<?> set) {
return "Super:hashSet";
}
}
static class Sub extends Super {
public static String getType(Collection<?> collection) {
// 我猜这一行应该是想返回"Sub:collection"
return "Sub";
}
}
}
A.
Sub:collection
Sub:collection
Sub:collection
B.
Sub:hashSet
Sub:arrayList
Sub:collection
C.
Super:collection
Super:collection
Super:collection
D.
Super:hashSet
Super:arrayList
Super:collection
正确答案: C 你的答案: A (错误)
这道题目做错了真的不怪我啊,牛客网上的排版太乱了,代码又长,很难读完的。
这道题目其实涉及多个知识点:
首先它是通过了一个实例对象去调用静态方法,注意两个类中的方法都是静态的,而静态方法是不会被覆写的。
然后下面这部分代码,要确定到底调用的是哪个类中的getType方法:
Super subToSuper = new Sub();
for (Collection<?> collection : collections) {
System.out.println(subToSuper.getType(collection));
}
第一行就属于静态分派,new了一个Sub
对象,但将其声明为Super
类型的引用,这就属于编译期间确定好的类型,也称为“静态分派”。那么可以确定,后面调用的getType
方法,实际上是调用了Super
类型的静态方法,但到底是哪个重载版本呢?
其实后面这个也是静态分派,因为第二行代码中Collection<?> collection : collections
也显式地将从集合中取出来的对象声明为了Collection
类型的引用,所以调用的重载方法版本就是参数为Collection类型的。
布尔型居然可以用位运算?
我一直以为布尔型位运算只存在于C语言这种语言中,直到我遇见了这道题:
题目:
根据下面的代码,
String s = null;
会抛出NullPointerException异常的有()。
A. if( (s!=null) & (s.length()>0) )
B. if( (s!=null) && (s.length()>0) )
C. if( (s==null) | (s.length()==0) )
D. if( (s==null) || (s.length()==0) )
正确答案: A C 你的答案: A C (正确)
虽然我是选对了,因为我知道根据短路原则BD必不可能嘛,但是我还真不知道布尔型可以用位运算。
然后我就试了一下这些代码:
System.out.println(true&true);
System.out.println(false&true);
System.out.println(false&false);
System.out.println(true|true);
System.out.println(false|true);
System.out.println(false|false);
发现都是可以正常执行的,并且输出依次为:
true
false
false
true
true
false
可见和逻辑运算的结果并没有差别,那么true和false底层是通过1和0来表示吗?我在网上搜了一下,有一个人是这么说的:
JVM虚拟机规格标准第二版规定:字节码形态的boolean的false和true,是用int(32bit整型)的0和1表示
那么就假定这是正确的,但通过实验,布尔类型不能和整型互转,也不能参与整型的运算。不是很明白JVM这样设计的用意。
那么谈到这里,和题目一比较,大概就知道了,这样的位运算符运用在布尔类型上和逻辑运算符的区别就是没有短路原则,可以做个实验验证一下:
public static void main(String[] args) {
System.out.println(true|returnFalse());
}
public static boolean returnFalse(){
return false;
}
写一段这样的代码,经过调试发现,会执行到returnFalse
这个方法中去。所以说是没有短路原则的。
原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/java%e5%9f%ba%e7%a1%80%e6%9f%a5%e7%bc%ba%e8%a1%a5%e6%bc%8f02/