mixpplus
11/18/2019 - 7:02 AM

面向对象

static修饰的成员不能访问没有static修饰的成员

在static方法中不能使用this super关键字

匿名对象调用非静态方法:
new Person().say()

可变长参数:
public void function(String...books){};

方法重载: 两同一不同
同类同方法名 参数列表不同(参数个数、参数类型)

var p = new Person(); 新语法?

高内聚低耦合指的是?
一个程序有50个函数,这个程序执行得非常好;然而一旦你修改其中一个函数,
其他49个函数都需要做修改,这就是高耦合的后果。

方法重写:两同两小一大
两同: 方法名相同 形参列表相同 
两小: 子类方法返回值类型应该比父类返回值类型更小或者相等
子类方法声明抛出的异常类应该比父类方法声明抛出的异常类更小或者相同
一大: 子类方法的访问权限应该比父类方法的访问权限更大或者相等
注意:覆盖方法和被覆盖方法要么都是类方法要么都是实例方法

super 和this一样不能写在static修饰的方法内

继承:
在子类继承父类情况下,经过子类重写的父类方法会被隐藏,如果想要在子类调用父类被隐藏的方法
(实例方法):super.methodname 
(类方法): 父类名.methodname

在子类中: 可以使用父类名直接调用父类的类变量或者类方法。


子类调用父类的构造器可以使用super(args1, args2)必须放在方法首行
同类中调用重载的构造器可以使用this(args1,args2)必须放在首行。


在继承中:
子类在创建对象时会调用子类的构造方法,但在调用自己的构造方法之前如果没有显示调用父类的带参构造方法
就默认调用父类的无参构造器,如果显示调用父类构造器,则会寻找符合条件的构造器,然后执行子类构造器
所以: 父类中要么不写构造器(默认会有一个无参数构造器),要么重写有参构造器,然后把无参数构造器显示写出来。
简单记忆: 只要在父类中重载了构造器就必须把无参数构造器加上。

子类对象是父类实例  
使用instanceof时 两边需要有继承关系 父类类型转子类类型需要强制转换。

boolean result = obj instanceof Class
其中 obj 为一个对象,Class 表示一个类或者一个接口,当 obj 为 Class 的对象,
或者是其直接或间接子类,或者是其接口的实现类,结果result 都返回 true,否则返回false。

 注意:编译器会检查 obj 是否能转换成右边的class类型,如果不能转换则直接报错,如果不能确定类型,则通过编译。
	如果obj是null那么直接返回false



在多态中,成员变量不具有多态性 成员方法具有多态性。

继承: is-a  在整体类中增强功能(增加属性) 用继承
组合: has-a  在两个类中存在明确的整体与部分关系时 用组合
组合和继承相比并不会有更大的开销。

如果需要在子类对象调用父类被重写的方法,可以在子类中新建一个方法并且用super.fatherfunction()。

引用类型: 只有在向下类型转换时才需要强制转换 SonClass sonobj = (SonClass)fatherobj 父类对象转成子类对象需要强制转换

初始化块只在创建java对象时隐式执行,并且在执行构造器之前。

创建对象时,java程序去执行构造器,但在执行构造器之前会检查有没有实例变量和初始化块,如果有会优先执行
实例变量或者初始化块,这二者执行顺序与代码顺序一致。


1)子类是不继承父类的static变量和方法的。因为这是属于类本身的。但是子类是可以访问的。 
2)子类和父类中同名的static变量和方法都是相互独立的,并不存在任何的重写的关系。


静态初始化块 初始化块 构造器执行顺序:

1. 静态初始化块的优先级最高,也就是最先执行,并且仅在类第一次被加载时执行;
2. 非静态初始化块和构造函数后执行,并且在每次生成对象时执行一次;
3. 非静态初始化块的代码会在类构造函数之前执行。因此若要使用,应当养成把初始化块写在构造函数之前的习惯,便于调试;
4. 静态初始化块既可以用于初始化静态成员变量,也可以执行初始化代码;
5. 非静态初始化块可以针对多个重载构造函数进行代码复用。


不同线程调用方法为什么是线程安全的。局部变量存储在栈中,
静态成员变量存储在方法区,非静态成员变量存储在堆区),
为什么局部变量不能够static修饰等(局部变量存储在栈区,在方法调用时不能够自动初始化必须由程序员手动初始化,
否则会报错,归根结底是由于static变量和局部变量存储的位置不一样。)。

protected:

1、在同一个包中, 普通类或者子类都可以访问基类的 protected 方法。(同包和default相同)
2、不同包下,在子类中通过父类引用不可以访问其 protected 方法 
(无论是创建 Parent 对象还是通过多态创建 Son1 对象, 只要 Parent引用,则不可访问,编译器会提示错误。)
只能通过该子类对象访问父类protected方法
3、 不同包下,在子类中不能通过另一个子类引用访问共同基类的 protected 方法 (只能是该子类去访问父类protected方法)
4、对于protected的静态变量或者方法, 在子类中可以直接访问, 在不同包的非子类中则不可访问


通过String s = "";方式创建的String对象放进常量池 常量池中相同的字符串内容是同一个对象

涉及到字符串连接一般使用StringBuilder
常用方法 insert  append toString  delete(int start, int end) 

final是最终的意思,修饰类,属性,方法。
1. 不允许final变量重新赋值
2. 子类不允许覆盖父类final方法
3. final类无法派生子类。
4、 final修饰的直接赋值的变量才可以是宏变量(编译时就可以确认为常量) final int a = 10;

经过final修饰的成员变量必须由程序员指定初始值,无法使用系统默认分配的初始值(一经指定初始值无法更改)
指定初始值可以在定义该变量时指定 或者在初始化块中指定 或者在构造器中指定
final成员变量在没有初始化之前是不能直接调用取值的,但是可以通过一个方法来获取,可以理解为java设计的缺陷!

经过final修饰的方法可以重载 但是不能被子类重写

(1)编译时异常(检查异常,编译器强制捕获并处理):IO异常(比如java.io.FileNotFoundException),SQL异常
(2)运行时异常(发生在运行阶段,编译器不强制捕获也不处理):NullPointerException
(使用null字符串的长度,用null字符串equals(某字符串))、ArithmeticException(整数除以0)、IndexOutOfBoundsException
(3)错误:Java.lang.Error?编译器错误一般都是语法错误! 


String				chatAt	endsWith	equals	hashCode	indexOf isEmpty	lastIndexOf	length	replace  
					replaceFirst	split	startsWith	substring	toLowerCase	toString toUpperCase	trim	valueOf
					
StringBuilder		append	capacity	chatAt	delete	deleteCharAt	indexOf	insert	lastIndexOf	length	replace reverse
					setCharAt	setLength	substring	toString	trimToSize

ArrayList			add	addAll	clear	clone	contains	ensureCapacity	get indexOf	isEmpty	lastIndexOf	remove removeAll
					set size	sort	subList	trimToSize	toArray

					
在含有静态初始化块和成员变量和普通初始化块和在构造器中含有super关键字时的调用顺序:
在继承中,创建子类对象时程序会先判断整个继承树中是否含有静态初始化块,如果有,会优先执行(实际上此过程是在创建对象之前完成的,并且
在整个生命周期内只加载一次),然后程序会走到需要创建对象的构造器,判断是否含有super关键字,如果有,程序走到super指定的父类构造器,
(如果继承树中还有父类,继续往父类构造器走)但是在执行父类构造器之前还需要判断在父类中是否含有成员变量和普通初始化块
(这两者执行顺序与代码顺序相同),如果有,则优先执行普通初始化块或者成员变量。


抽象类和抽象方法:

含有抽象方法的类一定是抽象类 抽象类中可以没有抽象方法
抽象方法不能含有方法体
抽象类不能够被实例化
子类继承抽象类必须要完全实现抽象方法 否则本身也成为抽象类

abstract修饰类时表明此类只能被继承 修饰方法时表明此方法必须由子类提供实现
final修饰的类不能被继承 final修饰的方法不能被重写 因此:
final和abstract永远不能同时使用

abstract和static不能同时修饰方法 但二者并非永远互斥,他们可以同时修饰内部类
abstract和private不能同时使用(abstract修饰的方法只能由子类重写)


接口:

接口可以有多个直接父接口
接口名字通常是形容词
接口只能继承接口,不能继承类
接口中只能存在 静态常量 抽象方法 静态方法 默认方法或者私有方法 内部类(包括内部接口 枚举)
在接口中定义的成员变量总是被public static final修饰
接口中的普通方法总是被public abstract修饰 且不能有方法实现 但是类方法 默认方法 私有方法必须有方法实现
接口中定义的内部类,内部接口 内部枚举默认采用public static修饰
接口中的默认方法就是有方法体的实例方法 该方法使用default修饰 但是默认权限是public 此时的default不是权限修饰符
接口中的类方法需要使用static修饰 访问权限依然是public 类方法可以直接用接口来调用


接口与抽象类的区别:
1、 接口里面只能包含抽象方法、静态方法、默认方法、私有方法,不能为普通方法提供方法实现
抽象类则完全可以包含普通方法。
2、 接口里只能定义静态常量,不能定义普通成员变量;抽象类里则既可以定义普通成员变量,也可以定义静态常量。
3、 接口里不包含构造器;抽象类里可以包含构造器,抽象类中的构造器并不能用于创建对象,而是让其子类调用这些构造器
来完成属于抽象类的初始化操作。
4、 接口中不能包含初始化块;但抽象类则完全可以包含初始化块
5、 一个类最多只能有一个直接父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补java单继承的不足。


判断字符串能否转换为int类型:

public boolean canParseInt(String str){
if(str == null){ //验证是否为空
return false;

}

return str.matches("\\d+"); 
//使用正则表达式判断该字符串是否为数字,第一个\是转义符,
\d+表示匹配1个或 //多个连续数字,"+"和"*"类似,"*"表示0个或多个

}



接口:
接口中的成员变量默认修饰符 public static final
接口中的成员方法默认修饰符 public abstract

类与类是继承关系 extends 只能是单继承
类与接口是实现关系 implements 可以是多实现, 在实现的同时可以继承父类,继承关键字必须在implements之前
接口与接口是继承关系 可以是单继承也可以是多继承


多态:
静态方法和成员变量不具有多态性

在多态中 父类引用指向子类对象, 父类引用无法访问子类中独有的方法,否则在编译阶段就会出现错误
在向下转型时应该先使用instanceof判断一下是否为该类的对象,在进行强制转换,否则容易出现类型转换异常。
例如:
Fu f = new Zi();
// 访问子类中独有的方法 直接使用f.method()是访问不到的
if(f instanceof Zi){
	Zi zi = (Zi)f;
	zi.method();
}


方法引用:

引用静态方法						ContainingClass::staticMethodName
引用某个对象的实例方法				containingObject::instanceMethodName
引用某个类型的任意对象的实例方法	ContainingType::methodName
引用构造方法						ClassName::new


System:
System.identityHashCode(obj) 通过obj对象的地址值计算出hashCode值,所以只要两个对象的identityHashCode值相同,那么就是同一个对象


获取java程序的运行时环境:
Runtime rt = Runtime.getRunTime();
// 获取处理器数量:
rt.availabalProcessors();
// 获取空闲内存:
rt.freeMemory();
// 获取总内存数:
rt.totalMemory()
// 获取可用最大内存数:
rt.maxMemory();

Runtime对象还可以直接运行某些命令:
rt.exec("notepad.exe")



非静态内部类:
非静态内部类中不能有静态成员;
创建内部类对象:
外部类.内部类 变量名 = 外部类对象.内部类对象
Out.Inner inner = new Out().new Inner();

在内部类中的实例方法中 访问该方法中的局部变量可以直接调用 weight
访问该内部类的实例变量 使用this.weight
访问外部类的实例变量 使用 Outer.this.weight

静态内部类:
静态内部类只能访问外部类中的类成员 不能访问外部类中的普通成员 否则编译出错
静态内部类可以看做外部类的静态成员 所以外部类是可以访问静态内部类中的成员的
在外部类中访问内部类的静态成员 通过内部类名.内部类静态成员
在外部类中访问内部类的普通成员 通过内部类对象.内部类普通成员。

在外部类以外的地方 创建静态内部类对象:
外部类名.内部类名 变量名 = new 外部类名.内部类名();

注意: 在接口中定义内部类 默认修饰符为 public static


枚举类:
关键字 enum 是一种特殊的类
枚举类默认继承java.lang.Enum 所以枚举类不能显示继承其他父类。
非抽象枚举类默认使用final修饰 所以枚举类不能够派生子类
枚举类构造器默认使用private修饰 显示指定也只能是private
枚举类的所有实例必须在枚举类的第一行显示列出 系统会自动为这些实例添加public static final修饰。
枚举类默认提供了values()方法,返回所有枚举值,是一个该类的数组。
枚举类中有一个特殊的方法values()找不到实现体,返回一个该枚举类的数组,从而可以通过索引访问到枚举对象。

1. 所有枚举类都是Enum的子类
2. 我们可以通过"枚举类名.枚举项名称"去访问指定的枚举项
3. 每一个枚举项其实就是该枚举的一个对象
4. 枚举也是是一个类,也可以去定义成员变量
5. 枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,但是如果枚举类有其
	他的东西,这个分号就不能省略。建议不要省略
6. 枚举类可以有构造器,但必须是private的,它默认的也是private的。枚举项的用法比较特
	殊:枚举("");
7. 枚举类也可以有抽象方法,但是枚举项必须重写该方法


自定义枚举类举例:

public enum Season {

    SPRING("春天"){
        @Override
        public void show() {
            System.out.println("sprint...");
            System.out.println(this.name);
        }
    },
    SUMMER("夏天"){
        @Override
        public void show() {
            System.out.println("summer...");
            System.out.println(this.name);
        }
    },
    AUTUMN("秋天"){
        @Override
        public void show() {
            System.out.println("autumn...");
            System.out.println(this.name);
        }
    },
    WINTER("冬天"){
        @Override
        public void show() {
            System.out.println("winter...");
            System.out.println(this.name);
        }
    };

	// 如果该变量是私有的,在内部类中访问不到。
    public String name;

    private Season(String name){
        this.name = name;
    }
    public abstract void show();
}

注意: 
上面自定义枚举类中有一个抽象方法,并且每一个枚举值都是该枚举类中的一个对象,在创建枚举类对象时必须实现抽象方法,
所以可以使用内部类的方式创建子类对象并且重写抽象方法,因为是内部类(也就是子类),所以在内部类中访问不到外部的私有
成员变量。



枚举类中常用的方法:

String name() 		// 获取枚举项的名称

int ordinal() 		// 返回枚举项在枚举类中的索引值

int compareTo(E o) 	// 比较两个枚举项,返回的是索引值的差值

String toString() 	// 返回枚举常量的名称

static <T> T valueOf(Class<T> type,String name) // 获取指定枚举类中的指定名称的枚举值

values() // 获取所有的枚举项  返回数组类型



垃圾回收:

垃圾回收机制只会回收堆内存中的对象, 不会回收任何物理资源(数据库连接 网络io等资源)。
程序无法精确控制垃圾回收的运行,垃圾回收会在合适的时候进行,当对象永久失去引用后,垃圾回收机制会在
合适的时候进行回收。
在垃圾回收机制回收对象之前,总是会调用它的finalize()方法,该方法可能是对象重新复活(变量重新引用该对象),
从而导致垃圾回收机制取消回收该对象。

程序无法控制垃圾回收的时机,但是可以通知垃圾回收机制运行,到底垃圾回收机制运行不运行,这是无法确定的。
通知垃圾回收机制启动有两种方式:
1、 System.gc();
2、 Runtime.getRuntime().gc();


关键字介绍:
strictfp: 精确浮点的意思 正常浮点数精确度比较低 使用该关键字会严格执行IEEE-754提升浮点数的精确度
native: 使用native关键字的程序会失去跨平台的特性 使用native修饰的方法类似于抽象方法,
不同的是native方法通常采用c语言来实现,通常用来访问系统硬件等。

规则:
abstract 和 final永远不可能同时使用;
abstract 和 static 不能同时修饰方法, 但可以同时修饰内部类;
abstract 和 private 不能同时修饰方法, 但可以同时修饰内部类;
private 和 final同时修饰方法语法是合法的, 但是没有意义, private修饰的方法不能被子类重写,所以final失去了意义;


Math类:
Math类包含了许多数值运算相关的方法;
Math.random() 产生伪随机数 [0.0, 1.0) 返回值double类型;

Random类:
Random类主要用来产生伪随机数,有两个构造器, 一个构造器默认使用的种子是当前时间(用种子来生成随机数),
另一个使用程序员显示传入一个long型的整数种子。
注意: 只要传入的种子相同,那么产生的随机数对象也是相同的,产生的随机数也是相同的,为了避免产生相同的
随机数,通常使用当前时间(默认)来生成随机数。

ThreadLocalRandom类:
该类是Random的扩展类 主要用于多线程环境下,是线程安全的,用法与Random基本一致。
该类提供了一个静态的current()方法,来获取ThreadLocalRandom对象。获取对象之后用法与Random对象用法基本一致。

BigDecimal:
可以表示高精度浮点数,要求数值精度较高时用此类。
通过BigDecimal构造器创建对象时,优先使用String类型的构造器,这样产生的结果时可预知的。
如果使用浮点数的构造器产生BigDecimal对象,结果不可预知,例如传入0.5,
会传入一个无限接近0.5的数值,而不是真正的0.5;
如果必须使用浮点数来创建对象,可以使用BigDecimal的静态方法来创建,BigDecimal.valueOf(0.5);

该类的常用方法:
add(), subtract(), 	multiply(), devide(), pow();
注意:
divide(BigDecimal divisor, int scale, RoundingMode roundingMode) 该方法如果不设置scale和roundingMode的
话遇到除不尽会抛异常
scale:保留小数点后的位数;
roundingMode:进位模式 该类为枚举类 UP:直接进1  FLOOR:直接去尾  HALF_UP:四舍五入;


Calender:
由于Date类设计有缺陷,所以官方推荐使用Calender处理日期时间相关事务;
该类是一个抽象类,只能通过getInstance() 类方法来创建该类实例
常用方法:
abstract void add(int field, int amount)  : 
根据日历的规则,将指定的时间量添加或减去给定的日历字段,如果该字段值超出或少于界限值,相应的上级单位或者
下级单位也需要做出改变
注意: 可以看到该方法是一个抽象方法,实际上当使用Calendar.getInstance() 返回的对象是
Calendar的子类GregorianCalendar的对象,该类实现了add()等抽象方法。

void roll(int field, int amount)   :
根据日历的规则,将指定的时间量添加或减去给定的日历字段,如果该字段值超出或少于界限值,相应的
下级单位也需要做出改变,上级单位不变。
void set(int field, int value) :
设置某个字段的值;
void set(int year, int month, int date)  :
设置年月日;
void set(int year, int month, int date, int hourOfDay, int minute)  :
设置年月日时分
void set(int year, int month, int date, int hourOfDay, int minute, int second) 
设置年月日时分秒;
void setLenient(boolean lenient)  :
设置容错性,true: 表示允许容错,当字段设置值超出所允许范围,会使上级或者下级字段做出改变
			false: 表示不允许容错, 当字段设置值超出所允许的范围时,会导致运行时异常;

注意: 设置月份的时候,月份值的范围是[0,11], 所以0代表 1月 ,年份和日期没有此规定。

set方法修改字段值都是延时生效的,虽然字段的值是立即生效,但是该日期对象所代表的的时间却不是立即生效
直到下次调用add() roll() getTime() getTimeInMillis() get() 才会重新计算日期,
好处: 频繁的字段设定减少不必要的中间层日期计算。


正则表达式:

1、 先产生Pattern对象,该对象是由Pattern.compile("regex")方法产生,方法内是匹配规则;
2、 由Pattern对象产生Matcher对象,该对象由 pattern.matcher(strs)方法产生,
	括号内为需要匹配的目标字符串,执行匹配的状态保存到matcher对象中。
3、 产生matcher对象之后,可以使用该对象的方法进行查找,替换,查找位置等操作;
4、 多个matcher可以共享一个pattern
matcher对象的常用方法:
matcher.find()					是否找到匹配规则的子串;
matcher.replaceAll("str")		把所有匹配到的子串全部替换成str,返回新的字符串;
matcher.replaceFirst("str")		把第一个匹配到的子串替换成str,返回新的字符串;
matcher.group()					返回上一次匹配到的子串,可用于循环中(配合matcher.find())
matcher.reset("str")			按照相同的匹配规则去匹配新的字符串str;					
matcher.start()					返回上一次匹配到的子串在目标字符串的开始位置;
matcher.end()					返回上一次匹配到的子串在目标字符串的结束位置+1;
matcher.lookingAt()				判断目标字符串是否是以匹配规则开始的字符串 类似于String中的starsWith();				
matcher.matches()				返回整个目标字符串是否与匹配规则匹配。




堆 栈 方法区:

栈: 每个线程都会有一个栈区 所以是线程安全的。
0. 局部变量和引用变量存储在栈中。  
1. 每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象)。对象都存放在堆区中。 
2. 每个战中的数据(基础数据类型和对象引用)都是私有的,其他栈不能访问。 
3. 栈分为3个部分:基本类型变量,执行环境上下文,操作指令区(存放操作指令). 
4. 在函数中定义的一些基本类型的变量数据和对象的引用变量都在函数的栈内存中分配。 
5. 当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当该变量退出该作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。
 
堆: 所有线程共享同一份堆内存, 所以线程不安全。
1. 存储的全部是对象,每个对象包含一个与之对应的class信息–class的目的是得到操作指令。 
2. jvm只有一个堆区(heap)被所有线程共享,堆区中不存放基本类型和对象引用,只存放对象本身。 
3. 堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,
	Java的垃圾收集器会自动收走这些不再使用的数据。 
4. 缺点是,由于要在运行时动态分配内存,存取速度较慢。
5.常量池在堆中。
6. 堆中有: 对象 静态区 常量池
静态区(静态区在堆中):
1. 只要是静态的都在静态区



方法区: 所有线程共享同一份堆内存, 所以线程不安全。
存放所有的
1、类(class),
2、普通成员方法和普通成员变量
3、普通初始化块


每个线程栈内存初始大小为1M;


倒序方法实现:
Arrays.sort(T[] a, Comparator<? super T> c) 方法倒序的实现: T 表示引用数据类型

Arrays.sort(arr, new Comparator<>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                if (o1 < o2) {
                    return 1;
                } else if (o1 > o2) {
                    return -1;
                } else {
                    return 0;
                }
            }
        });
使用匿名内部类重写Comparator中的compare()方法;
倒序:
第一个参数< 第二个参数 返回 1
第一个参数 > 第二个参数 返回 -1
两者相等返回 0;

正序(系统默认):
第一个参数< 第二个参数 返回 -1
第一个参数 > 第二个参数 返回 1
两者相等返回 0;

更简单的方式:
Arrays.sort(arr, (b,a)-> a.compareTo(b));
前后参数一致会使用默认的正序排序,前后顺序相反会使用倒序方式排序;




异常处理:
格式:
try{

} catch(){

} finally{

}

解释:
try语句块中的代码出现异常时,会抛出对应的异常对象,catch块用来捕获异常对象
catch块中的()里面写try里面可能会抛出的异常对象,一个catch块中可以同时写多个类型的异常,异常类型之间
用|分割,捕获多种异常时,异常变量有隐式的final修饰,所以不可以修改该异常对象,一个catch块中一个异常类型
则没有隐式final修饰,所以可以对异常变量修改。

finally:
除非在try或者catch块中强制退出虚拟机(System.exit(0)),否则无论如何都会执行finally代码,即使是return;

注意: 
不要在finally语句块中使用return或者throw等导致方法终止的语句,否则会使try或者catch语句中的return或者throw
失去作用,程序执行到try或者catch语句中的return或者throw会先判断有没有finally语句,如果没有就执行return或者
throw退出,如果有就去先执行finally语句块,finally执行完毕再反过来执行try或者catch中的return或者throw语句,
如果此时finally中有return或者throw会导致该方法直接结束,try或者catch中的return或者throw得不到执行。



举例:
try{
            int a = 10;
            int b = 0;
            System.out.println(a/b);

        }catch (IndexOutOfBoundsException | NumberFormatException e){
            e = new ArithmeticException("test"); // 不可修改异常变量
        }catch (Exception e){
            e = new ArithmeticException("test"); // 可以修改异常变量
            
        } finally {
            System.out.println("不管是否出现异常都会执行");
        }

访问异常信息:
getMessage()  					异常详细描述字符串
printStackTrace()				异常的跟踪栈信息输出到标准输出
printStackTrace(PrintStream s)	异常的跟踪栈信息输出到指定输出流
getStackTrace()					返回该异常的跟踪栈信息


自动关闭资源的try,catch:

格式:
try(资源变量或者创建资源变量的语句){

}catch(){

} finally{

}

注意:使用自动关闭资源的try或者catch会有一个隐式的finally用于关闭资源,所以这种格式可以省略catch和finally
如果程序需要,也可以带上。


编译时异常:
在编译阶段发生的异常,如果不处理编译通不过,更不会执行。



编译时异常类的特点:

调用抛出编译时异常的方法:
如果在某个方法中显式抛出了编译时异常,则说明在调用该方法时需要用try,catch来捕获异常,
或者在调用方也需要显式抛出该异常类或者该异常子类,否则出错。

方法重写时抛出异常的限制:(两小) 针对编译时异常来说
子类方法声明抛出的异常类型应该是父类方法声明抛出的异常类型或者子类型。
子类方法声明抛出的异常不允许比父类方法声明抛出的异常类型多,可以相等。



数值比较:

1.System.out.println(127==127); //true , int type compare
2.System.out.println(128==128); //true , int type compare
3.System.out.println(new Integer(127) == new Integer(127)); //false, object compare
4.System.out.println(Integer.parseInt("128")==Integer.parseInt("128")); //true, int type compare
5.System.out.println(Integer.valueOf("127")==Integer.valueOf("127")); //true ,object compare, because IntegerCache return a same object
6.System.out.println(Integer.valueOf("128")==Integer.valueOf("128")); //false ,object compare, because number beyond the IntegerCache
7.System.out.println(Integer.parseInt("128")==Integer.valueOf("128")); //true , int type compare

解释

int整型常量比较时,== 是值比较,所以1,2返回true。1,2是值比较。
new Integer() 每次构造一个新的Integer对象,所以3返回false。3是对象比较。
Integer.parseInt每次构造一个int常量,所以4返回true。4是值比较。
Integer.valueOf返回一个Integer对象,默认在-128~127之间时返回缓存中的已有对象(如果存在的话),
所以5返回true,6返回false。5,6是对象比较。
第7个比较特殊,是int 和 Integer之间的比较,结果是值比较,返回true。

总结

对于整型的比较,首先判断是值比较还是对象比较,值比较肯定返回true,有一个是值就是值比较。
对象比较,则看对象是怎么构造出来的,如果是采用new Integer方式,则每次产生新对象,
两个new出来的Integer比较肯定返回false,如果是Integer.valueOf方式的话,注意值的区间是否在-128~127之间,
如果在,则构造的相同值的对象是同一个对象,==比较后返回true,否则返回false。
所以,对于值比较==放心没问题,对于Integer的比较最好用equals方法比较对象内容,当然注意先判断Integer是否不为null。



List转数组

ArrayList<String> list=new ArrayList<String>();
String[] strings = new String[list.size()];
list.toArray(strings);

数组转List:
String[] s = {"a","b","c"};
List list = java.util.Arrays.asList(s);


Set转数组:
Set<Integer> set = new HashSet<>();
set.add(10);
set.add(30);
set.add(20);

Integer[] arr = new Integer[set.size()];
set.toArray(arr);
此时的arr就是已经被转换的数组;

数组转Set:

Integer[] arr = new Integer[10];
Set<Integer> set = new HashSet<>();
set.addAll(Arrays.asList(arr));



java1.7以后添加新特性:

1.try .. catch

try(实现了AutoCloseable的对象){
// 代码逻辑
}catch(异常类名 变量名) {
// 异常处理代码
}


2.接口中的方法:
允许有 :
抽象方法:   默认public abstract修饰
静态方法:	只能用该接口名字调用
默认方法:	实现类继承和重写二选一,如果实现类实现的多个接口中含有相同的默认方法,那么实现类必须重写该默认方法
私有方法:	主要提供给默认方法和静态方法使用;


3. Collection 和Map中创建不可变集合 of方法 静态 参数最多十个或者十对K-V
Collection.of()  
Map.of()

4. Collections工具类中将可变集合转成不可变集合:

public static <T> Collection<T> unmodifiableCollection(Collection<? extends T> c) 
将一个可变的单列集合转换成不可变的单列集合

public static <K,V> Map<K,V> unmodifiableMap(Map<? extends K, ? extends V> m) 
将一个可变双列集合转换成不可变的双列集合


5. java9在InputStream中提供了一个方法transferTo该方法可以从该输入流中读取所有字节,并按
读取的顺序将字节写入给定的输出流

InputStream inputStream = new FileInputStream("D:\\a.avi"); // 创建字节输入流
OutputStream out = new FileOutputStream("F:\\a.avi") ;// 创建字节输出流
inputStream.transferTo(out) ;


6. Stream中新的方法
public static<T> Stream<T> ofNullable(T t) 
构建包含一个元素的流对象,元素可以为null,如果为null返回一个空流; 可以防止空指针异常
Stream<Object> objectStream = Stream.ofNullable(null);

takeWhile方法:
default Stream<T> takeWhile(Predicate<? super T> predicate) 
截取第一个不满足条件之前的元素,不包含不满足条件的元素

// 截取操作,截取第一个不满足条件之前的元素
Stream.of(23, 45, 67, 88, 12, 34, 45).takeWhile(x -> x <=67).forEach(s -> System.out.println(s));

dropWhile方法:
default Stream<T> dropWhile(Predicate<? super T> predicate) 
截取第一个不满足条件之后的元素,包含不满足条件的元素

// 截取操作,截取第一个不满足条件之后的元素
Stream.of(23, 45, 67, 88, 12, 34, 45).dropWhile(x -> x <=67).forEach(s -> System.out.println(s));

7. Optional类:
Optional类是java8提供的一个类,该类的主要作用就是让我们以更优雅的方式去防止空指针异常
(NullPointerException);

常见方法:
public static <T> Optional<T> of(T value)
返回一个Optional对象,封装的是非null值的对象

public T get()
如果存在值,返回值,否则抛出 NoSuchElementException

public boolean isPresent()
判断Optional所封装的对象是否不为空,如果不为空返回true , 否则返回false

public static <T> Optional<T> ofNullable(T value)
返回一个Optional对象,Optional封装的值对象可以是null也可以不是nul

public T orElse(T other)
如果存在值,则返回值,否则返回other

public T orElseGet(Supplier<? extends T> supplier)
如果存在值,则返回值,否则返回由供应函数产生的结果

public void ifPresent(Consumer<? super T> action)
如果存在值,则使用该值执行给定的操作,否则不执行任何操作。

public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)
如果存在值,则使用该值执行给定的操作,否则执行给定的基于空的操作。


8. ProcessBuilder:
通过java程序去执行一个windows的exe可执行程序

public ProcessBuilder(String... command)
创建一个ProcessBuilder对象,command表示要执行的命令

public Process start() 
启动程序,返回的是一个进程的描述对象Process

public ProcessHandle.Info info() 
调用Process对象的获取ProcessHandle.Info对象

ProcessHandle.Info中的方法:
Optional<String[]> arguments() 返回进程参数的Strings数组
Optional startInstant() 开始时间
Optional user() 返回进程的用户
Optional command() 返回进程的可执行路径名


类成员变量、普通成员变量、初始化块、构造方法的初始化和执行顺序:

Father静态成员变量初始化
Father静态初始化块

Son静态成员变量初始化
Son静态初始化块

Father普通成员变量
Father普通初始化块
Father构造函数

Son普通成员变量
Son普通初始化块
Son构造函数