x=x+1,x+=1,x++ x++效率最高;x=x+1需4步,x+=1需3步,x++需2步。
Java中涉及byte、char和short类型的运算操作首先会把这些值转换为int类型,然后对int进行运算,最后得到int类型结果。
short s=1;s=s+1; 错误 short s=1;s+=1; 正确
public class Test { public static void main(String args[]){ char a; a = '*'; System.out.println(a); int ia = (int)a; System.out.println(ia); a += a; System.out.println(a); } } * 42 T
assert Expression1:Expression2
assert断言默认不开启,需加参数-enableasserttions或-ea。
Expression1不通过则抛java.lang.AssertionError异常打印Expression2
error和exception的区别:
error表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。
exception表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。
反射可以在运行时加载、探知、使用编译期间完全位置的classes。换句话说,java程序可以加载一个运行时才得知名称的class、获悉其完整构造(但不包括methods定义),并生成其对象实例、或对其fields设值,或唤起其methods。
final、finally、finalize区别
final修饰的变量初始化有2个地方,一是其定义处,二是在构造函数中,两者只能选其一;
final修饰的方法有两个原因:一是不允许从此类继承的类来覆写这个方法,但是继承仍然可以继承这个方法,也就是说可以直接使用;二是允许编译器将所有对次方法的调用转化为inline(行内)调用的机制,但要注意程序代码迅速膨胀。
String的形参传递:
public class test { public static void main(String[] args) { String str = "hello"; changeStr(str); System.out.println(str); } public static void changeStr(String str){ str += "1"; } } //Output:hello
字符串是值传递。Sring的本质是一个值,如果把值当作一个仓库的话,函数就是在某块空地(栈的临时存储区)上重建了一个一模一样的仓库。原来的仓库假设为A,后面的仓库假设为B。当changeStr函数中str改变时只是改变仓库B里面的屋子。这有点像基本类型。
类内访问私有成员
public class Test { private int court; Test(int i){ court = i; } public static void main(String[] args) { Test t = new Test(99); System.out.println(t.court); } } //Output:99
定义在类内的变量会被赋予一个默认的值
public class Test { static boolean b; public static void main(String[] args) { System.out.println(b); } } //Output:false
从键盘接收输入数据:
public class Test { static String getInput(){ String str = ""; BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); try{ str = br.readLine(); } catch(IOException e){ return "IOException"; } return str; } public static void main(String[] args) { System.out.println(getInput()); } }
判断一个整数是不是2的阶次方:
public class Test { static void check(int d){ if( ((d-1)&(d))==0 && (d!=0) ) System.out.println("ok"); else System.out.println("false"); } public static void main(String[] args) { check(64); } }
switch的参数是byte、char、short、int、enum。
Heap和Stack区别
堆是运行时数据区,类的对象从中分配空间。
栈数据可以共享(int a=3;会先在站中查找有没有3),栈中数据大小与生存期必须是确定的,栈主要存放一些基本类型的变量和引用。
String是一个特殊的包装类数据,String str = new String("abc");新创建一个对象 String str = "abc";会先从常量池查找有没有存放“abc”,有则指向。
String str1 = "abc"; String str2 = "abc"; str1==str2 -----> true
String str1 = new String("abc"); String str2 = new String("abc"); str1==str2 -----> false
HashMap和Hashtable
Hashtable是线程安全的。
HashMap没有分类或排序,允许一个null键和多个null值,Hashtable不允许null键和null值。
HashMap将Hashtable的contains()去掉,改成containsvalue(),containskey()
内部类或嵌套类在类层级上没有限制,内部类可以是私有类。
重载overload:
每个重载方法的参数的类型和(或)数量必须是不同,返回类型并不足以区分所使用的是哪个方法。
Java的自动类型转换也适用于重载方法的自变量,例如只有test(double),test(int i = 88)则会调用到test(double)。只有找不到精确匹配时,Java的自动转换才会起作用。
继承的方法修饰词static,final
父类的final、static方法会继承到子类,子类可以调用但不能覆盖;
子类可以重新定义与父类static方法一样的方法(含static关键字),当子类不能重新定义与父类final方法一样的方法(含final关键字)。
Only constructors can invoke constructors.子类的构造函数如果要引用super的话,必须把super放在构造函数的首位。this()同理,只能出现在被构造函数调用,且只能出现在第一行。
子类构造函数调用父类构造函数时,注意父类构造函数会调用子类的多态函数,同时注意变量不会有多态、父子类重名变量的可见性:
class Base{ int i; Base(){ add(1); System.out.println(i); } void add(int v){ i += v; System.out.println(i); } } class MyBase extends Base{ // int i = 1; MyBase(){ add(2); } void add(int v){ i += v*2; System.out.println(i); } } public class Test { public static void main(String args[]){ go(new MyBase()); } static void go(Base b){ b.add(8); } } //output:2 2 6 22 //去掉注释的结果值得注意 output:2 0 5 21
首先执行new MyBase(),调用父类构造函数Base();在Base()中执行add()方法,这里需要注意,这个add方法由于实在新建MyBase对象时调用的,所以会首先查找MyBase类中是否有次方法,所以Base()函数中的add(1)实际上执行的是
void add(int v){
i += v*2;
System.out.println(i);
}
同时注意变量i在父类变化会带到子类。
注意到程序中的注释部分,若去掉注释,则在执行上面流程时,在Base()函数调用add(1),i是MyBase中定义的i,此时i还没有被初始化,所以是0。若在MyBase定义了i,则在MyBase类中见到的i是在MyBase类定义的i,同时注意初始化问题。
数组没有length()这个方法,有length属性,String有length()方法。
String与char的比较:
import java.util.Arrays; public class Test { public static void main(String args[]){ String s = "hello"; String str = "hello"; char c[] = {'h', 'e', 'l', 'l', 'o'}; char ch[] = str.toCharArray(); //String转换成char[] if(s.equals(ch)) System.out.println("true"); else System.out.println("false"); //1 if(ch == c) System.out.println("true"); else System.out.println("false"); //2 if(ch.equals(c)) System.out.println("true"); else System.out.println("false"); //3 if(Arrays.equals(ch, c)) System.out.println("true"); else System.out.println("false"); //4 String s2 = new String(c); //char[]转换成String if(s2 == (s)) System.out.println("true"); else System.out.println("false"); //5 if(s2.equals(s)) System.out.println("true"); else System.out.println("false"); //6 } } false false false true false true
1,char和String是两种不同的类型,所以比较结果不同;
3,在数组上调用equals,就是Object里面的方法,比较的是两个对象的地址,而c和ch地址不同;
4,用Arrays.equals(a,b)就能比较两个数组内容;
String.intern()
public class Test { public static void main(String args[]){ String s1 = "hello"; String s2 = new String("hello"); s2 = s2.intern(); System.out.println(s1 == s2); } } true
在常量池查找内容相同(equals())的字符串,查找不到则在常量池加入字符串。
String文字池(pool of literal strings)
由于字符串对象的大量使用(它是一个对象,一般而言对象总在heap分配内存),Java中为了节省内存空间和运行时间,在编译阶段就把所有的字符串文字放到一个文字池中,而运行时文字池成为常量池的一部分。文字池的好处就是该池中所有相同的字符串常量被合并,只占用一个空间。
以下创建了几个对象?
String A, B, C; A = "a"; B = "b"; A = A + B; StringBuffer D = new StringBuffer("abc"); D = D.append("567");
数组声明不能直接指定行数或列数,应该是在创建数组对象时定义数组的行数和列数,二维数组可以列数不同:
int iArray[][] = new int[3][4]
synchronized和java.util.concurrent.locks.Lock异同
同:Lock能完成synchronized所实现的所有功能;
异:Lock比synchronized更精确的线程语义和更好的性能。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。
JAVA接口中对于字段会加上隐式的public,static,final,方法会加上public,abstract