复习
1.线程的生命周期
线程从创建到结束的过程:生命周期。
新建、就绪、运行、消亡、阻塞
在Thread类中:getState(),可以获取当前线程某一时刻真实的状态
2.线程池
理解: 存储线程对象的一个容器。
有任务来临,从池中取出一个空闲的线程去执行任务,任务执行结束,线程回到线程池,等待接受下一个任务。
代码:
ExecutorService es = Executors.newFixedThreadPool(number) : 创建最多number个数线程对象的的
线程池对象
ExecutorService:
submit(线程任务) :线程任务(实现Runnable,实现Callable)
shutdown():关闭线程池
shutdownNow():关闭线程池
3.类加载器
当使用类加载器加载一个class文件时,会为这个class文件创建一个Class对象
这个Class对象中封装了方法,可以用于获取该class文件中的内容信息,如:属性、构造方法、方法…
加载器的继承:
Bootstrap ClassLoader : 核心类库,如:String 、System...
--Ext ClassLoader : 加载就是ext文件夹中的类
--App ClassLoader : 简单理解:加载我们自己写的类
加载类采用的是:双亲委派机制
4.反射理解
在运行时,可以动态获取加载到内存中的类的内容,对获取到的内容进行想要的操作。
源头:Class对象
5.获取Class对象
java.lang.Class
任何类型都有Class对象,基本类型、引用类型、void
方式:
1.类型.class
2.new 类名().getClass()
3.Class.forName(“包名.类名”)
6.通过反射实现对象的创建
1.Class类中有一个 newInstance() 方法,可以创建Class表示的类型的对象,前提是该类型必须有无参数构造方法。
创建对象:必然要调用构造方法。
2.Class类中的getConstructor()…方法,可以获取到Constructor对象
Constructor就是用于描述构造方法这类事物的
一个Constructor实例代表一个构造方法
Constructor中有一个 newInstance(… initargs)方法,通过这个方法可以执行Constructor表示的构造方法,即创建对象
课程
一. 反射应用
(一) 反射获取成员变量并使用
在这里插入代码片
1.Class类获取成员变量对象:
Field[] getFields()
返回所有公共成员变量对象的数组
Field[] getDeclaredFields()
返回所有成员变量对象的数组
Field getField(String name)
返回单个公共成员变量对象,参数name表示成员变量的名字
Field getDeclaredField(String name)
返回单个成员变量对象,参数name表示成员变量的名字
2.Field类型: 表示一个成员变量类型,每个对象都是一个具体的成员变量
作用: 获取成员变量的各种信息(修饰符、注解、名称),做各种数据类型的转换.
3.Field类用于给成员变量赋值的方法:
set(Object obj, Object value): 用于给obj对象的,指定成员变量,赋value值
4.Field类获取成员变量值的方法:
get(Object obj): 用于获取obj对象的指定成员变量值
package com.ujiuye.day;
public class Person {
private String name;
public int age;
private char gender;
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", gender=" + gender +
'}';
}
public void show(){
System.out.println("show");
}
private void method(){
System.out.println("method");
}
}
package com.ujiuye.day;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class Demo1 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
/*
* 通过反射,实现类中的属性(字段)获取
* 1.获取Class对象
* 2.获取字段
* 3.操作获取的字段(赋值和取值)
*
* 字段,即属性也是一类事物,因此有对应的类描述该类事物,----Field
* 一个Field对象代表的是一个属性,属性属于某个对象,因此要对属性进行操作,需要有对象
* set(对象,属性值)。
* Object get(对象)
* */
Class<?> aClass = Class.forName("com.ujiuye.day.Person");
//已知字段的名字格式
Field name = aClass.getDeclaredField("name");
//System.out.println(name);
name.setAccessible(true);
Person p = (Person) aClass.newInstance();
name.set(p,"xiaohong");
System.out.println(name.get(p));
System.out.println(p);
Field[] fields = aClass.getFields();//获取公共字段
Field[] fields = aClass.getDeclaredFields();//获取所有字段
Person p = (Person) aClass.newInstance();
//age
fields[1].set(p,18); //赋值
System.out.println(p);
Object value = fields[1].get(p); //取值
System.out.println(value);
//name --private
fields[0].setAccessible(true);
fields[0].set(p,"zhangsan"); //赋值
System.out.println(fields[0].get(p)); //取值
System.out.println(p);
for (int i = 0; i < fields.length; i++){
//修饰符 数据类型 名
String mod = Modifier.toString(fields[i].getModifiers());
String typeName = fields[i].getType().getTypeName();
String name = fields[i].getName();
System.out.println(mod+" "+typeName+" "+name);
}
}
}
(二) 获取类中的成员方法并执行
1.Class类获取成员方法对象:
Method[] getMethods()
返回所有公共成员方法对象的数组,包括继承的
Method[] getDeclaredMethods()
返回所有成员方法对象的数组,不包括继承的
Method getMethod(String methodName, Class<?>...parameterTypes)
返回单个公共成员方法对象
Method getDeclaredMethod(String methodName, Class<?>...parameterTypes)
返回单个成员方法对象
2.Method类型:
(1) 表示成员方法的类型,该类型的每个对象,都是一个具体的成员方法
(2) 成员方法对象具有的功能: 获取成员方法信息,运行方法.
3.Method类用于执行方法的功能:
invoke(Object obj, Object…values):调用obj对象的成员方法,参数是values是运行方法的实际参数,返回值Object类型是方法运行的返回值结果.
(三) 暴力反射
1.通过Class类中:
getDeclaredXXX方法: 可以获取类中所有声明的成员(属性、方法、构造),私有的成员也可以获取到.但是私有成员进行访问使用时,会因为权限问题导致失败,因此就需要暴力反射解决访问私有的问题
2.修改该对象的访问权限:
AccessibleObject类是Field,Method和Constructor对象的基类. 它提供了将反射对象标记为在使用它时抑制默认Java语言访问控制检查的功能.
setAccessible(boolean flag): true的值表示反射对象应该在使用时抑制Java语言访问检查,false的值表示反映的对象应该强制执行Java语言访问检查.
3.一旦设定当前对象可以访问,私有的成员也可以被访问,被修改.
package com.ujiuye.day;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Demo2 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
/*
* 获取类中的成员方法
* 方法也是一类事物,就有对应的类来进行描述,——————Method
* 一个Method对象代表一个方法
* 想要Method表示的方法被执行,可以通过Method类中的invoke
* Object invoke(对象,参数值);
* */
Class<?> aClass = Class.forName("com.ujiuye.day.Person");
//获取方法
//Method[] methods = aClass.getMethods();//获取所有的公共方法,包括继承
Method[] methods = aClass.getDeclaredMethods(); //获取当前类中的所有方法,不包括继承
Person per = (Person) aClass.newInstance();
/*
* public java.lang.String toString(){}
public java.lang.String getName(){}
public void setName(java.lang.String args0){}
private void method(){}
public int getAge(){}
public void setAge(int args0){}
public char getGender(){}
public void setGender(char args0){}
public void show(){}
* */
String s = (String)methods[0].invoke(per); // 无参 有返回值
System.out.println(s);
methods[2].invoke(per,"小红"); //有参 无返回值
System.out.println(per);
//暴力反射
methods[3].setAccessible(true);
methods[3].invoke(per); //无参 无返回值
for (int i = 0; i < methods.length; i++){
//修饰符 返回值类型 方法名 (参数列表) throws 异常类型名 {}
String mod = Modifier.toString(methods[i].getModifiers());
String reName = methods[i].getReturnType().getName();
String name = methods[i].getName();
System.out.print(mod+" "+reName+" "+name+"(");
//参数列表
Class<?>[] parameterTypes = methods[i].getParameterTypes();
if(parameterTypes.length == 0){
System.out.print(")");
}else {
for (int j = 0; j < parameterTypes.length; j++){
if(j != parameterTypes.length -1) {
System.out.print(parameterTypes[j].getName() + " args" + j + ",");
}else{
System.out.print(parameterTypes[j].getName() + " args" + j + ")");
}
}
}
//异常
Class<?>[] exceptionTypes = methods[i].getExceptionTypes();
if(exceptionTypes.length == 0){
System.out.print("{}");
}else{
System.out.print("throws ");
for (int k = 0; k < exceptionTypes.length; k++){
if(k != exceptionTypes.length -1) {
System.out.print(exceptionTypes[k].getName() + ",");
}else{
System.out.print(exceptionTypes[k].getName() + "{}");
}
}
}
System.out.println();//换行
}
}
}
package com.ujiuye.day;
import java.lang.reflect.Method;
public class Demo3 {
public static void main(String[] args) throws Exception {
//获取单个方法
Class<?> aClass = Class.forName("com.ujiuye.day.Person");
//参数: 方法名 参数列表类型--Class
Method me = aClass.getDeclaredMethod("setName", String.class) ;//获取类中的任何权限的单个方法,不包括继承
Person per = (Person) aClass.newInstance();
me.invoke(per,"xiaoming");
Method me1 = aClass.getDeclaredMethod("getName");
Object value = me1.invoke(per);
System.out.println(value);
System.out.println(per);
}
}
package com.ujiuye.day;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class Demo4 {
public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
ArrayList<String> list = new ArrayList<>();
list.add("abc");
list.add("123");
/* list.add(666);*/
//通过反射
Class<? extends ArrayList> aClass = list.getClass();
Method method = aClass.getMethod("add", Object.class);
method.invoke(list,666);
System.out.println(list);
}
}
二. JDK新特性
(一) 接口的新特性
1. 概述:
jdk8之前接口是规则的集合体,方法只有抽象方法。
jdk8版本开始不光有抽象方法同时增加了实体方法。
2. 增加内容:
jdk8:default默认方法, static静态方法
jdk9: private私有方法
1.1 默认方法
-
被关键字 default 修饰的方法就是默认方法,是在jdk8版本才出现的方法,独属于接口所有。
-
出现的原因:在jdk8版本的时候,需要对一个接口下面的所有的实现类的功能做一个增强,就需要在接口当中去添加方法,如果接口中添加的是抽象方法,下面的实现类就需要强制去重写这些抽象方法,jdk希望在接口当中添加方法,直接就让下面的实现类去使用,不用再次的进行重写,所以添加了使用default做修饰的默认方法,默认方法是可以不被重写的,因为他有方法体。
-
语法格式:
修饰符 default 返回值类型 方法名 (参数列表){方法体}
-
使用规则:
(1) 加上default的,实现类可以不重写,直接调用
(2) 特殊情况1:实现类实现了两个接口,如果有相同的默认方法声明,则强制要求在实现类中,重写这个方法,以指定确定的实现内容
(3) 特殊情况2:在特殊情况1中,如果在实现类重写这个方法的过程中,希望指定其中某一个接口的默认实现,则可以调用”父接口名.super.默认方法名称(实际参数)”
(4) 特殊情况3:实现类实现了继承了一个父类,并且实现了一个接口,并且在父类中和接口中,有相同的方法声明,则“类优先”。即使继承的是一个抽象类,也是使用父类的实现(即强制重写)。 -
产生的影响
(1) 接口中如果也可以定义非抽象方法,那么接口和抽象类的差别就越来越小
(2) java中一个类只能继承一个抽象类,但是可以同时实现多个接口,所以有了默认方法,就会让大量的抽象类变成接口,即弱化了抽象类
1.2 静态方法
1、接口的静态方法可以定义方法体内容
2、static不能和abstract共存
3、外界只能通过接口名称.静态方法来访问接口静态方法
4、实现类中不会继承接口中的静态方法,原因:如果一个类同时实现了两个接口,具有相同的静态方法名,继承之后不知道应该以哪个为准, 而静态方法又不能重写,因此矛盾无法解决
1.3 私有方法
- 概述: 私有方法是jdk9版本增加的一个实体方法,主要是用来进一步封装代码,提升相关代码安全性的手段。私有化之后方法不能被实现类直接调用使用或重写修改,只能提供给接口的静态方法和默认方法使用。
- 使用:
(1) 普通私有方法:只能提供给默认方法调用使用
(2) 静态私有方法:默认方法和静态方法都可以调用
静态方法只能使用静态的私有方法,不能使用普通的私有方法
package com.ujiuye.day;
/*
* jdk8的新特性
* 1.接口
* 8前接口: 常量、抽象方法
* 8后接口: 常量 抽象方法 默认方法(带有方法体的方法) 静态方法(不重写,不继承)
* 9后接口: 新增private修饰的方法。
* 实现接口:
* 抽象方法一定要抽象,否则实现类是抽象类
* 默认方法可以重写也可以不重写
*
* 说明:
* 1.一个类可以实现多个接口,如果多个接口中有相同的默认方法的声明,方法主体不同,那么实现必须重写该方法
* 2.针对上边的1,如果重写的方法中想要调用指定的接口中的该方法,那么: 父接口名.super.方法名(实参);
* 3.一个类可以继承另一个类,实现多个接口,采用的是“类优先”原则
* 比如:父类中和接口中有相同的方法声明,方法体不同,创建子类对象,调用这个方法,执行的是父类中的方法
* 在子类中,该方法可以不重写。
* */
public class Demo5 {
public static void main(String[] args) {
/* InterA in = new MyInter();
in.show();
in.method();
InterA.fun();*/
new MyInter().show();
}
}
interface InterA{
public static final int NUM = 100;
public abstract void method();
//8开始
default void show(){
System.out.println("A-show");
}
static void fun(){
System.out.println("fun");
}
}
interface InterB{
default void show(){
System.out.println("B-show");
}
}
class Inter{
public void show(){
System.out.println("父---show");
}
}
class MyInter extends Inter implements InterA,InterB{
@Override
public void method() {
System.out.println("method");
super.show();
InterB.super.show();
}
/* @Override
public void show(){
InterA.super.show();
InterB.super.show();
System.out.println("show");
}*/
}
(二) Lambda表达式
2.1 概述
- 本质:
Lambda表达式是java对数学函数表达式的一种体现形式,本质是一个值,在java中主要是体现在对特殊的匿名内部类对象的一种表示,代表匿名内部类的对象 - 使用前提:
函数式接口:只有一个抽象方法的接口(可以有其他非抽象方法)
可以在接口声明之上, 使用注解: @FunctionalInterface标识验证这个函数式接口 - 好处:
对匿名内部类对象的格式简化,大幅提升开发效率
注: Lambda表达式代表的匿名内部类的对象,在编译的时候不需要生成对应类的字节码文件,而匿名内部类在编译的时候需要编译生成对应的字节码文件,所以Lambda表达式可以提高效率
2.2 格式详解
-
格式:
(参数列表) -> {方法体}
-
详细说明:
(1) (参数列表): 表示要实现的接口中,抽象方法的参数
(2) -> : 箭头运算符,或者称为Lambda运算符,用于分隔前后两部分
(3) {方法体}: 也称为Lambda体,表示重写抽象方法的具体实现
2.3 特殊情况
-
有且只有一个参数,可以省略小括号
x -> {int result = x * x; System.out.println(x + “的平方为:” + result);}
-
Lambda体只有一句,且没有返回值,可以省略大括号
x -> System.out.println(x * x);
-
Lambda体只有一句,且有返回值,则return和大括号可以一起省略
(x, y) -> {return x + y;} 等价于 (x, y) -> x + y
注意:要么一起省略,要么都不省略
package com.ujiuye.day;
/*
* Lambda表达式:
* 其实就是一个简写格式,匿名内部类的简写格式,本质是一个值,可以当做数据一样进行方法传递
* 匿名内部类语法格式:
* new 父类名/父接口名(){
* 重写方法;
* }
* 匿名内部类:创建一个匿名的子类对象
* 要求是:只针对接口,并且这个接口中的抽象方法个数必须是1
* 默认方法或静态方法个数不限。
*
* */
public class Demo6 {
public static void main(String[] args) {
//匿名内部类形式
Runnable run = new Runnable() {
@Override
public void run() {
System.out.println("run");
}
};
new Thread(run).start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("run");
}
}).start();
Runnable run1 = () -> System.out.println("run1");
new Thread(run1).start();
new Thread(() -> System.out.println("run1")).start();
}
}
package com.ujiuye.day;
public class Demo7 {
public static void main(String[] args) {
Runnable run = new Runnable() {
@Override
public void run() {
System.out.println("run");
}
};
Runnable run1 = () -> System.out.println("run");
new Thread(run1).start();
/*
* Lambda表达式:
* 使用一个固定符号, 箭头符号 ->
* 将表达式分成左右两边部分,左边部分就是接口中的抽象方法的参数列表,右边部分就是方法的实现代码。
* */
}
}
package com.ujiuye.day;
import java.util.Comparator;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
/*
* 匿名内部类会有class文件生成
* Lambda表达式,没有class文件生成。
* */
public class Demo8 {
public static void main(String[] args) {
//无参 无返回值 --Runnable
Runnable run = new Runnable() {
@Override
public void run() {
System.out.println("run");
}
};
Runnable run1 = () -> {
System.out.println("run1");
};
Runnable run2 = () -> System.out.println("run1");
//Lambda体 有且只有一条语句时,大括号可省略
//有参 无返回值 --Consumer
Consumer<String> con = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
Consumer<String> con1 = (String s) -> System.out.println(s);
Consumer<String> con2 = s -> System.out.println(s);
//Lambda参数 有且只有一个时,小括号和参数类型都可以省略
//有参 有返回值 --Comparator
Comparator<Integer> com = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1-o2;
}
};
Comparator<Integer> com1 = (Integer o1, Integer o2) -> {
return o1-o2;
};
Comparator<Integer> com2 = (Integer o1, Integer o2) -> o1-o2;
Comparator<Integer> com3 = (o1, o2) -> o1-o2;
//Lambda体 有且只有一条语句时并且这条语句有return,大括号和return都可以省略
//Lambda参数 有多个参数时,小括号不可以省略,但是参数类型可省略
//无参 有返回值 --Callable
Callable<String> call = new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println("hahha");
System.out.println("heihei");
return "call";
}
};
Callable<String> call1 = () -> {
System.out.println("hahha");
System.out.println("heihei");
return "call1";
};
}
}
/*interface TestA{
void test();
}
interface TestB{
void test(String s);
}*/