2019-06-06 Java学习日记 day27 反射
类的加载概述和加载时机
类的加载
*当程序要使用某个类时,如果该类还没被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化
*加载
*就是指将class文件读入内存,并为之创建class对象。任何类被使用时系统都会建立一个class对象
*连接
*验证 是否有正确的内部结构,并和其他类协调一致
*准备 负责为类的静态成员分配内存,并设置默认初始化值
*解析 将类的二进制数据中的符号引用替换为直接引用
*初始化
加载时机
*创建类的实例
*访问类的静态变量,或者为静态变量赋值
*使用反射方式来强制创建某个类或接口对应的java.lang.class对象
*初始化某个类的子类
*直接使用java.exe命令来运行某个主类
类加载器和分类
类加载器
*负责将.class文件加载到内存中,并为之生成对应的class对象。虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行
类加载器的分类
*Bootstrap ClassLoader 根类加载器
*Extension ClassLoader 扩展类加载器
*System ClassLoader 系统类加载器
类加载器的作用
*Bootstrap ClassLoader 根类加载器
也被称为引导类加载器,负责Java核心类的加载
比如System.String等,在JDk中JRE的lib目录下rt.jar文件中
*Extension ClassLoader 扩展类加载器
负责JRE的扩展目录中jar包的加载
在JDK中JRE的lib目录下ext目录
*System ClassLoader 系统类加载器
负责在JVM启动时加载来自java命令的class文件,以及classpath华宁变量锁指定的jar包和类路径
反射概述
JAVA反射机制是在运行状态,对于任意一个类,都能够知道这个类的所有属性和方法
对于任意一个对象,都能够调用它的任意一个方法和属性
这种动态获取的信息以及动态太哦用对象的方法的功能称为java语言的反射机制
要想解剖一个类,必须先要获取到该类的字节码文件对象
而解剖使用的就是class类中的方法,所以先要获取到每一个字节码文件对应的class类型的对象
三种方式
*object类的getClass()方法没判断两个对象是否是同一个字节码文件
*静态属性class,锁对象
*Clas类中静态方法forNamme(),读取配置文件
import tan.jung.bean.Person; public class demo1_Reflcet { public static void main(String[] args) throws ClassNotFoundException { Class clazz1=Class.forName("tan.jung.bean.Person"); Class clazz2 =Person.class; Person p =new Person(); Class clazz3=p.getClass(); System.out.println(clazz1 == clazz2); System.out.println(clazz2 == clazz3); } }
forName配置
import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; public class demo2_Reflect { public static void main(String[] args) throws Exception { //没有反射 //Juice j1=new Juice(); //购买榨汁机 //j1.run(new Apple()); //向榨汁机放入苹果 //j1.run(new Orange()); //Fruit f =new Orange //反射和配置 BufferedReader br1=new BufferedReader(new FileReader("cofing.prt")); Class clazz=Class.forName(br1.readLine()); Fruit f=(Fruit) clazz.newInstance(); //父类引用指向子类对象,水果引用指向了苹果对象 Juice j=new Juice(); j.run(f); } } interface Fruit{ public void squeeze(); } class Apple implements Fruit{ public void squeeze(){ System.out.println("榨出一杯苹果汁"); } } class Orange implements Fruit{ public void squeeze(){ System.out.println("榨出一杯橙子汁"); } } class Juice{ // public void run(Apple a){ // a.squeeze(); // } // // public void run(Orange o){ // o.squeeze(); // } public void run(Fruit f){ f.squeeze(); } }
通过反射获取带参构造方法并使用
*Constructor
*Class类的newInstance()方法是使用该类无参的构造函数创建对象,如果一个类没有无参的构造函数,就不能这样创建了,可以调用Class类的getConstructor(String.class,int.class)方法获取一个指定的构造函数然后再调用Constructor类的newInstance(“张三”,20)方法创建对象
import java.lang.reflect.Constructor; import tan.jung.bean.Person; public class demo3_Constructor { public static void main(String[] args) throws Exception { Class clazz =Class.forName("tan.jung.bean.Person"); //Person p =(Person) clazz.newInstance(); //通过无参创建对象 Constructor c =clazz.getConstructor(String.class,int.class);//获取有参构造 Person p=(Person) c.newInstance("张三",23); //通过有参构造创建对象 System.out.println(p); } }
通过反射获取成员变量并使用
*Field
*Class.getField(String)方法介意获取类中的指定字段(可见的),如果是私有的可以用getDeclaedField(“name”)放啊获取,通过set(obj,“李四”)方法可以设置指定对象上该字段的值,如果是私有的需要先调用setAccessible(true)设置访问权限,用获取的指定的字段套用get(obj)可以获取指定对象中该字段的值
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import tan.jung.bean.Person; public class demo4_Fiexd { public static void main(String[] args) throws Exception { Class clazz =Class.forName("tan.jung.bean.Person"); Constructor c =clazz.getConstructor(String.class,int.class);//获取有参构造 Person p=(Person) c.newInstance("张三",23); //通过有参构造创建对象 Field f =clazz.getDeclaredField("name"); f.setAccessible(true);//去除私有权限 f.set(p, "李四"); System.out.println(p); } }
通过反射获取方法并使用
*Method
*Class.getMethod(String,Class...)和Class.getDeclaredMethod(String,Class....)方法可以获取类中的指定方法,调用invoke(object,object...)可以调用该方法,Class.getMethod(“eat”)invoke(obj)Class.getMethod(“eat”.int.class)invoke(obj,10)
import java.lang.reflect.Constructor; import java.lang.reflect.Method; import tan.jung.bean.Person; public class demo5_method { public static void main(String[] args) throws Exception { Class clazz =Class.forName("tan.jung.bean.Person"); Constructor c =clazz.getConstructor(String.class,int.class); Person p=(Person) c.newInstance("张三",23); Method m =clazz.getMethod("eat"); //获取eat方法 m.invoke(p); Method m2=clazz.getMethod("eat", int.class); //获取有参的eat方法 m2.invoke(p, 10); } }
动态代理的概述和实现
概述
代理:本来应该自己做的事情,请人被人来做,被请的人就是代理对象
动态代理:在程序运行过程中产生的这个对象,而程序运行过程中产生的对象其实就是我们刚才反射讲解的内容,过意,动态代理其实就是通过反射来生成一个代理
在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理,我们有更强大的代理 cglib,Proxy类中的方法创建动态代理类对象
public static object newProxyInstance(ClassLoader) loader,Class< ? > [ ] interfaces,InvocationHandler h )
最终会调用InvocationHandler的方法
InvocationHandler object invoke(object proxy ,Method method,object[ ] args)
import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { /*userImp ui=new userImp(); ui.add(); ui.delete(); System.out.println("------------");*/ /*My m =new My(ui); user u=(user)Proxy.newProxyInstance(ui.getClass().getClassLoader(), ui.getClass().getInterfaces(), m); u.add(); u.delete();*/ StudentImp si=new StudentImp(); si.login(); si.submit(); System.out.println("------------"); My m =new My(si); Student u=(Student)Proxy.newProxyInstance(si.getClass().getClassLoader(), si.getClass().getInterfaces(), m); u.login(); u.submit(); } } //第二个包 public interface Student { public void login(); public void submit(); } //第三个包 public class StudentImp implements Student { @Override public void login() { System.out.println("登录"); } @Override public void submit() { System.out.println("提交"); } }
设计模式
概述
模板方法木事就是定义一个算法的骨架,而将具体的算法延迟刀子类中来实现
优点和缺点
优点:使用模板方法木事,在定义算法骨架的同时,可以很灵活的实现具体的算法,猫族用户灵活多变的需求
缺点:如果算法骨架有修改的话,则需要修改抽象类
装饰
单例
简单工厂
工厂方法
适配器
模板
JDK5的新特性
枚举概述
是指将变量的值——列出来,变量的值只限于列出来的值的范围内。
回想单列设计模式:单例类是一个类直邮一个实例
那么多列类就是一个类有多个实例,但不是无限个数的实例,而是有限个数的实例。这才能是枚举类
自动拆装箱
泛型
可变参数
静态导入
增强for循环
互拆锁
枚举
枚举的注意事项
定义枚举类要用关键字enum
所有枚举类都是Enum的子类
枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是尅省略的,但是如果枚举类其他的东西,这个分号就不能省略。建议不要省略
枚举类可以有构造器,单必须是private的,它默认的也是private的
枚举类也可以有抽象方法,但是枚举类必须重写该方法
枚举类在
switch语句中的使用
枚举的常见方法
int ordinal()
int compareTo(E o)
String name()
String toString()
<T> T valueOf (Class <T> type,String name)
values()
此方法虽然在JDK文档中查找不到,但每个枚举类都具有该方法,它遍历枚举类的所有枚举值非常方便
JKD7新特性
二进制字面量0b001
数字字面量可以出现下划线
switch 语句可以用字符串
泛型简化,菱形泛型
异常的多个catch合并,每个异常用或 |
try-with-resources 语句
JDK8新特性
接口中可以定义有方法体的方法,如果是非静态,必须用default修饰
如果是静态的就不用了