for 循环的执行顺序 1 2 3 4 5 6 7 8 9 10 11 12 13 static boolean foo (char c) { System.out.print(c); return true ; } public static void main (String[] args) { int i = 0 ; for (foo('A' );foo('B' )&&(i<2 );foo('C' )){ i++; foo('D' ); } }
try catch finally 当Java程序执行try块、catch块时遇到了return或throw 语句,这两个语句都会导致该方法立即结束,但是系统执行这两个语句并不会结束该方法,而是去寻找该异常处理流程中是否包含finally块,如果没有finally块,程序立即执行return或throw语句,方法终止;如果有finally块,系统立即开始执行finally块。只有当finally块执行完成后,系统才会再次跳回来执行try块、catch块里的return或throw语句;如果finally块里也使用了return或throw等语句,finally块会终止方法,系统将不会跳回去执行try块、catch块里的任何代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public static void main (String[] args) { System.out.println("return value of getValue(): " + getValue()); } public static int getValue () { int i = 1 ; try { i = 4 /0 ; }catch (Exception e){ i++; return i + 1 ; }finally { i++; return i - 1 ; } }
但是在遇到System.exit(0)
语句时finally语句不会执行
1 2 3 4 5 6 7 8 9 try { int i = 4 / 0 ; } catch (Exception e) { System.out.println("0" ); System.exit(0 ); } finally { System.out.println("1" ); }
同步问题 同步是害怕在操作过程的时候被其他线程也进行读取操作,一旦是原子性的操作就不会发生这种情况。
++x , x++ , x = y 都不是原子操作(都需要先取值在赋值),而 x = 1 原子操作
精度丢失 小范围转化为大范围的数值型变量,jvm在进行编译的过程中将进行类型的自动提升
大范围到小范围(向下转型)会丢失精度
范围大小依次是:byte、char、short、int、long、float、double
负数取绝对值还是负数 1 2 System.out.println(Math.abs(Integer.MIN_VALUE));
Double 1 2 3 System.out.println(Math.min(Double.MIN_VALUE, 0.0 )); System.out.println(1.0 / 0.0 ); System.out.println(0.0 / 0.0 );
byte 1 2 3 4 5 6 final byte a = 1 , b = 2 ; byte c = a + b; b = 127 ; byte c1 = a + b byte a1 = 1 , b1 = 2 ;byte c2 = a1 + b1;
三元运算符 1 2 3 Object o1 = true ? 1 : 1.0 ;System.out.println(o1);
BigDecimal的equals方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 BigDecimal bigDecimal1 = new BigDecimal ("0.1" );BigDecimal bigDecimal2 = new BigDecimal ("0.10" );System.out.println(bigDecimal2.equals(bigDecimal1)); BigDecimal bigDecimal3 = new BigDecimal (1 );BigDecimal bigDecimal4 = new BigDecimal (1.0 );System.out.println(bigDecimal3.equals(bigDecimal4)); System.out.println(bigDecimal1.compareTo(bigDecimal2));
跳出多层循环 1 2 3 4 5 6 7 8 9 10 flag: for (int i = 0 ; i < 10 ; i++) { for (int j = 0 ; j < 10 ; j++) { System.out.println("i=" + i + ",j=" + j); if (j == 5 ) { break flag; } } }
子类和父类
构造函数不能被继承,构造方法只能被显式或隐式的调用。
构造器的目的主要是为了构造对象,很显然父类的构造器只是为了给父类造对象的,但是我们通过继承extends关键字就已经继承到了父类的属性和方法,就不需要父类对象;
不知道你会不会想着在子类造父类对象,例如 子类类型 变量名 = new 父类类型( ); 先不说这样写有没有问题,我们就看有没有意义,在编译期这是个子类的类型,我们只能调用子类里的属性和方法,如果我们调用子类独有的属性和方法时,运行期发现实际上是父类类型 没有这个调用子类独有的方法和属性那么就会报错,如果这是调用父类中的属性和方法,那可以直接new子类对象就好了 没必要new父类;
调用的是父类 的static 方法或者字段
调用的是父类 的final 方法或者字段
通过数组来引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class P { public static int abc = 123 ; public static final String field = "final" ; public static String[] fields = {"final1" ,"final2" }; static { System.out.println("P is init" ); } static void hello () { System.out.println("hello ...." ); } final static void world () { System.out.println("world ...." ); } } public class S extends P { static { System.out.println("S is init" ); } } public class Test { public static void main (String[] args) { System.out.println(S.abc); S.hello(); System.out.println(S.field); S.world(); System.out.println(S.fields[0 ]); } }
只要是被子类重写的方法,不被super调用都是调用子类方法
String 对象的引用 String类型的常量池比较特殊。它的主要使用方法有两种: (1) 直接使用双引号声明 出来的String对象会直接存储在常量池中。
(2) 会在堆中创建对象,并在没被任何引用时回收
1 2 3 String b = new String ("b" ); ----- 使用intern 可以获取常量池数据地址 ----- String c = "a" .intern();
字符串拼接: (1) 如果时双引号 拼接则相当于直接赋值,存储在常量池
(2)引用对象拼接对象 在堆中创建对象
1 2 3 4 5 6 7 8 9 String a = "a" ;String b = "b" ; String str1 = "a" + "b" ;String str2 = a + b; String str3 = "ab" ;System.out.println(str1 == str2); System.out.println(str1 == str3); System.out.println(str2 == str3);
查看常量池 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 javap -c -verbose test.class Constant pool: #1 = Methodref #4. #13 #2 = String #14 #3 = Class #15 #4 = Class #16 #5 = Utf8 <init> #6 = Utf8 ()V #7 = Utf8 Code #8 = Utf8 LineNumberTable #9 = Utf8 main #10 = Utf8 ([Ljava/lang/String;)V #11 = Utf8 SourceFile #12 = Utf8 test.java #13 = NameAndType #5 :#6 #14 = Utf8 hello,world #15 = Utf8 test #16 = Utf8 java/lang/Object
烦人的空指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public String getStreetName ( Province province ) { if ( province != null ) { City city = province.getCity(); if ( city != null ) { District district = city.getDistrict(); if ( district != null ) { Street street = district.getStreet(); if ( street != null ) { return street.getName(); } } } } return "未找到该道路名" ; }
Optional语法专治上面的俄罗斯套娃式 if 判空 ,因此上面的代码可以重构如下:
1 2 3 4 5 6 7 8 9 public String getStreetName ( Province province ) { return Optional.ofNullable( province ) .map( i -> i.getCity() ) .map( i -> i.getDistrict() ) .map( i -> i.getStreet() ) .map( i -> i.getName() ) .orElse( "未找到该道路名" ); }
Thread 用start()来启动线程 ,实现了真正意义上的启动线程,此时会出现异步执行 的效果,即在线程的创建和启动中所述的随机性。 而如果使用run()来启动线程 ,就不是异步执行了,而是同步执行 ,不会达到使用线程的意义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Thread thread1 = new Thread (() -> { for (int i = 0 ; i < 5 ; i++) { System.out.println(i); } }); Thread thread2 = new Thread (() ->{ for (int i = 0 ; i < 5 ; i++) { System.out.println(i); } }); thread1.run(); thread2.run(); ================================================================= thread1.start(); thread2.start();
Object Object
中含有: getClass()、hashCode()、equals()、clone()、toString()、notify()、notifyAll()、wait(long)、wait(long,int)、wait()、finalize()
共十一个方法 。
equals
用于比较当前对象与目标对象是否相等,默认是比较引用是否指向同一对象 。为 public
方法,子类可重写。
clone
此方法返回当前对象的一个副本(生成新对象,但属性是原引用)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class demo implements Cloneable { private String name; private int age; @Override protected demo clone () throws CloneNotSupportedException { return (demo)super .clone(); } public static void main (String[] args) throws CloneNotSupportedException { demo john = new demo ("john" , 18 ); demo clone = john.clone(); System.out.println(clone == john); System.out.println(clone.getAge() == john.getAge()); System.out.println(clone.getName() == john.getName()); } }
List
Arrays.asList(不支持添加 和删除 ,修改会改变原数组 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 String[] s = {"1" , "2" , "3" }; List<String> list = Arrays.asList(s); list.add("4" ); list.set(0 , "0" ); System.out.println(Arrays.toString(s)); System.out.println(list.toString()); @SafeVarargs @SuppressWarnings("varargs") public static <T> List<T> asList (T... a) { return new ArrayList <>(a); } private static class ArrayList <E> extends AbstractList <E> implements RandomAccess , java.io.Serializable { } public void add (int index, E element) { throw new UnsupportedOperationException (); } public E remove (int index) { throw new UnsupportedOperationException (); }
修复办法 (套娃)
1 List<String> list = new ArrayList <>(Arrays.asList(arrays));
那原本的ArrayList就没有坑了吗
JDK 另一个方法 List#subList
生成新集合也会与原始 List
互相影响。
1 2 3 4 5 6 7 8 9 10 11 12 13 List<Integer> list = new ArrayList <>(); list.add(1 ); list.add(2 ); list.add(3 ); List<Integer> subList = list.subList(0 , 1 ); subList.set(0 , 10 ); System.out.println(list.toString()); System.out.println(subList.toString()); =================================================================== subList.add(4 ); System.out.println(list.toString()); System.out.println(subList.toString());
unmodifiableList不可集合真的不能变吗
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 List<String> list = new ArrayList <>(Arrays.asList("1" ,"2" ,"3" )); List<String> unmodifiableList = Collections.unmodifiableList(list); list.add("4" ); System.out.println(unmodifiableList.toString()); list.set( 0 , "10" ); System.out.println(unmodifiableList.toString()); list.remove( 0 ); System.out.println(unmodifiableList.toString());