错题一
- What will happen when you attempt to compile and run the following code?
public class Test{
static{
int x=5;
}
static int x,y;
public static void main(String args[]){
x--;
myMethod();
System.out.println(x+y+ ++x);
}
public static void myMethod( ){
y=x++ + ++x;
}
}
1、JVM加载class文件时,就会执行静态代码块,静态代码块中初始化了一个变量x并初始化为5,由于该变量是个局部变量,静态代码快执行完后变被释放;
2、声明了两个静态成员变量x,y,并没有赋初值,会有默认出值,int类型为0;
3、执行x--
操作,变量单独进行自增或自减操作x--
和--x
的效果一样,此时x变为了-1;
4、调用MyMethod()
方法,在该方法中对x和y进行计算,由于x和y都是静态成员变量,所以在整个类的生命周期内的x和y都是同一个;
5、y=x++ + ++x可以看成是y=(x++)+(++x),当++或者–和其它变量进行运算时,x++表示先运算,再自增,++x表示先自增再参与运算;所以此时x为-1参与运算,然后自增,x此时为0,++x后x为1,然后参与运算,那么y=-1+1就为0,此时x为1;
6、执行并打印x+y + ++x
运算方式和第5步相同,最后计算结果就为3;
错题二
- java 1.8开始支持接口中定义静态方法;
错题三
-
所谓的释放锁资源实际是:通知对象内置的
monitor
对象进行释放,而只有所有对象都有内置的monitor
对象,才能实现任何对象的锁资源都可以释放。 -
又因为所有类都继承自Object,所以
wait()
就成了Object方法,也就是通过wait()来通知对象内置的monitor对象释放,而且事实上因为这涉及对硬件底层的操作,所以wait()方法是native方法,底层是用C写的; -
其他都是Thread所有,所以其他3个是没有资格释放资源的,而
join()
有资格释放资源其实是通过调用wait()来实现的;
代码如下:
wait()方法
public final native void wait(long timeoutMillis) throws InterruptedException;
join()方法
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
错题四
-
this()和super()为构造方法,作用是在JVM堆中构建出一个对象。因此避免多次创建对象,同一个方法内只能调用一次this()或super()。
-
同时为了避免操作对象时对象还未构建成功,需要this()和super()的调用在第一行实现【以此来创建对象】,防止异常;
错题五
- 变量a是一个64位有符号的整数,初始值用16进制表示为:0x 7FFF FFFF FFFF FFFF;变量b是一个64位有符号的整数,初始值用16进制表示为:0x 8000 0000 0000 0000。则a+b的结果用10进制表示为多少?
1、a+b的16进制表示为:0x FFFF FFFF FFFF FFFF(16位F),转为2进制为111……111(64位1,每个F->4位2);
2、有符号数:是针对二进制来讲的。用最高位作为符号位,“0”代表“+”,“1”代表“-”。所以a+b的结果是一个负数。
3、计算机中负数是以补码的形式保存的,将补码转换成原码的计算方式如下:
①对于正数,原码与补码相同。
②对于负数,将补码除符号位之外,按位取反,末位加1,即得到原码。
4、a + b = 111……111(64位1)
取反:100……000(1位1,后面63位0)
加一:100……001(中间62位0)
10进制:-1
算法一
- 给定一个只包括
'(',')','{','}','[',']'
的字符串,判断字符串是否有效。有效字符串需满足:
左括号必须用相同类型的右括号闭合;
左括号必须以正确的顺序闭合;
注意空字符串可被认为是有效字符串;
public boolean isValid(String s) {
//1、如果当前元素是右括号:
// 栈中没有元素,返回false;
// 栈中最上面的元素不等于左括号,返回false
//2、不符合上面的条件的,也就是栈中元素和当前元素匹配,,栈中最上面的元素弹栈
//3、如果当前元素是左括号,进栈
//4、最终返回栈是否为空
int n = s.length();
if (n % 2 == 1) {
return false;
}
Map<Character, Character> pairs = new HashMap<Character, Character>() {{
put(')', '(');
put(']', '[');
put('}', '{');
}};
Deque<Character> stack = new LinkedList<Character>();
for (int i = 0; i < n; i++) {
char ch = s.charAt(i);
if (pairs.containsKey(ch)) {
if (stack.isEmpty() || stack.peek() != pairs.get(ch)) {
return false;
}
stack.pop();
} else {
stack.push(ch);
}
}
return stack.isEmpty();
}
这个题目使用栈结构做最合适,上面是官方的解法;
他的核心思路就是:
1、遍历字符串并判断当前元素如果是右括号:
- 栈中此时如果有元素不能匹配的返回false;
- 栈中没有元素返回false;
2、否则的话就是栈中最上面的元素与当前右括号匹配,将该元素弹栈;
3、如果当前元素是左括号,进栈;
4、最终返回栈是否为空,如果为空代表都匹配上了,否则没有全部匹配;
算法二
- 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
自己的做法:
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1 == null) {
return l2;
}
if(l2 == null) {
return l1;
}
LinkedList<Integer> list = new LinkedList<>();
while (l1 != null) {
list.add(l1.val);
l1 = l1.next;
}
while (l2 != null) {
list.add(l2.val);
l2 = l2.next;
}
list.sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
//System.out.println(list);
//[1, 1, 2, 3, 4, 4]
ListNode preNode = new ListNode(list.get(0));
for (int i = 1; i < list.size(); i++) {
ListNode listNode = new ListNode(list.get(i), preNode);
preNode = listNode;
}
return preNode;
}
我的思路是:
1、首先判断如果给定的链表为空,返回另一个列表;
2、进行两次while循环,将其中所有的值放进LinkedList列表中;
3、利用LinkedList的sort()将所有的元素从大到小存放;
4、创建结点preNode,该结点的值是列表的第一个元素的值;
5、遍历列表,取出其中的每个值,并将上一个结点元素一起放进一个新的结点;
6、让preNode指向该结点;
7、这样,最终preNode指向的是最后一个结点,又因为列表元素是从大到小,所有最终返回preNode正好符合从小到大规则;
这个做法在内存上效率较高,但是时间上较低;学习了其他人的做法,代码如下:
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) {
return l2;
}
else if (l2 == null) {
return l1;
}
else if (l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
}
else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
采用递归的做法:
一个方法执行完,返回结点,该结点赋值给调用该方法的一个结点的next;