Java基础笔记总结(19)-反射,枚举类 JDK1.7 1.8 新特性

反射

类的加载概述

程序要使用某个类,如果类还未加载到内存中,系统会通过加载,连接,初始化来实现对这个类进行初始化

加载,将class文件读入内存,并创建一个Class对象。任何类被使用时系统都会创建一个Class对象

连接

验证:是否有正确的内部结构,并和其他类协调一致

准备 负责为类的静态成员分配内存,并且设置默认值

解析 将类的二进制数据符号引用替换为直接引用

加载时机

创建类的实例

访问类的静态变量,或者为静态变量赋值

调用类的静态方法

使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

初始化某个子类

直接使用java.exe来运行某个主类

--------------------------------------------------------------------------------------

类加载器分类:负责将.class文件加载到内存中,并为之生成对应的Class对象

类加载器分类:

Bootstrap ClassLoader 根类加载器 引导类加载器 java核心类的加载System String 在jdk下的jre中的rt.jar

Extension ClassLoader 扩展类加载器 负责jre扩展目录下的jar包的加载,在JDK中JRT的lib目录下的ext目录加载

System ClassLoader 系统类加载器 负责在JVM启动时候加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径

------------------------------------------------------------------------------------

反射概述

JAVA反射机制就是在运行过程中,对任意一个类,都能知道这个类所有的属性和方法

对于任意的一个对象,都能够调用它的任意一个方法和属性

这种动态获取信息以及动态调用对象方法的方式成为JAVA的反射机制

想要解刨一个类,必须要获取到该类的字节码文件对象

而解刨使用的就是Class类中的方法,所以要获取每一个字节码文件对应的Class文件

三种方式

Object类的getClass()方法,判断两个对象是否是同一个字节码文件

静态对象class,锁对象

Class类中的静态方法,读取配置文件

源文件阶段      字节码文件          创建配置文件

Person.java    Person.class        Person p = new Person();

Class clazz = class.forName("类名");

Class clazz = Person.class;

Class clazz = p.getClass();

读取配置文件,只改配置文件就可以获取不同的属性和方法

字节码文件 当作静态方法锁对象

判断是否是同一个字节码对象

------------------------------------------------------------------------------------

Class.forName()读取配置文件

榨汁机Juicer榨汁,分别有水果 苹果 香蕉 橘子 榨汁

package com.ysu.reflect;

import java.io.BufferedReader;

import java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.IOException;

public class Reflect {

public static void main(String[] args) throws ClassNotFoundException, IOException, InstantiationException, IllegalAccessException {

//没用反射,只在使用动态

// Juicer juicer = new Juicer();

// juicer.run(new Apple());

// 用发射和配置文件

BufferedReader br = new BufferedReader(new FileReader("config.properties"));

Class clazz = Class.forName(br.readLine());

Fruit f = (Fruit) clazz.newInstance(); //父类引用指向子类对象

Juicer juicer = new Juicer();

juicer.run(f);

}

}

interface Fruit{

public void squeeze();

}

class Juicer {

public void run(Fruit f){

f.squeeze();

}

}

class Apple implements Fruit{

@Override

public void squeeze(){

System.out.println("榨出一杯苹果汁");

}

}

class Orange implements Fruit{

public void squeeze(){

System.out.println("榨出橘子酱");

}

}

------------------------------------------------------------------------------------

反射获取构造方法

Constructor

Class类的newInstance()方法是使用该类无参数的构造方法创建对象,一个类没有无参数构造函数,不能使用该方法,但是可以调用Class类的getConstructor()创建

获取有参构造创建对象

Class clazz = Class.forName("com.ysu.reflect.Person");

Constructor c= clazz.getConstructor(int.class,String.class);

Person p = (Person) c.newInstance(23,"张三");

System.out.println(p);

----------------------------------------------------------------------------------

通过反射获取成员变量

Class clazz = Class.forName("com.ysu.reflect.Person");

Method method = clazz.getMethod("eat");

Person p = (Person) clazz.newInstance();

method.invoke(p);

Method method2 = clazz.getMethod("eat", int.class);

method2.invoke(p, 10);

------------------------------------------------------------------------------------

通过反射越过泛型检查(泛型擦除)

ArrayList 中添加一个字符串对象

ArrayList list = new ArrayList<>();

list.add(11);

//泛型只在编译器有效,在运行期会被擦除掉

// list.add("abc");

Class clazz = Class.forName("java.util.ArrayList"); //获取字节码对象

Method m = clazz.getMethod("add", Object.class);//获取add方法

m.invoke(list, "abc");

System.out.println(list);

--------------------------------------------------------------------------------

修改通用属性方法

package com.ysu.reflect;

import java.lang.reflect.Field;

public class Tool {

public void setProperty(Object obj,String propertyName,Object value) throws Exception, Exception{

// 获取字节码对象

Class clazz = obj.getClass();

// 暴力反射获取字段

Field f = clazz.getDeclaredField(propertyName);

f.setAccessible(true);

f.set(obj, value);

}

}

-------------------------------------------------------------------------------------

1、xxx.properties获取属性类

2、利用反射获取相关属性,并运行方法

-------------------------------------------------------------------------------------反射的动态代理

package com.ysu.reflect;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler {

private Object target;

public MyInvocationHandler(Object target) {

this.target = target;

}

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

System.out.println("1111");

// 執行被代理的Target

method.invoke(target, args);

System.out.println("2222");

return null;

}

}

-----------------------------------------------------------------------------------

package com.ysu.reflect;

import java.lang.reflect.Proxy;

public class Test4 {

public static void main(String[] args) {

UserImp ui = new UserImp();

//动态代理

// 本来自己要做的请别人做,被请的人就是代理对象

// 在程序运行过程中产生这个对象,而程序运行过程中产生的对象就是我们刚才反射讲解的内容,所以动态代理就是通过反射生成一个代理

// Proxy 和 InvocationHandler接口,通过类和接口可以生成动态代理对象

MyInvocationHandler m = new MyInvocationHandler(ui);

User u = (User) Proxy.newProxyInstance(ui.getClass().getClassLoader(), ui.getClass().getInterfaces(), m);

u.add();

u.delete();

}

}

-----------------------------------------------------------------------------------

末班模式

就是定义一个算法的骨架,将具体的算法延迟到子类实现,抽象类不希望被重写的方法用final修饰

如果有算法骨架需要被修改的话,有抽象类

------------------------------------------------------------------------------------

枚举抽象类

一共有三种方法

利用单例模式

class Week {

  public staitc  Week MON = new Week();

  private Week(){}

}

class abstract Week2{

  public staitc final Week MON = new Week(){

public void show(){

System.out.println();

}

    }

  private Week(){}

  public abstract void show();

}

--------------------------------------------------------------

第一种 创建Enum类,直接写入对象就可以实现

第二种 public enum Week2{

MON("")

private String name;

private Week2(String name){

this.name = name;

}

}

//可以写入get set方法

测试 Week mon = Week.MON ;

第三种是写入方法,用匿名实现子类方法

public enum Week3{

MON(""){

public void show(){

System.out.println("xxxxxxx");

}

};

private String name;

private Week2(String name){

this.name = name;

}

}

测试 Week mon = Week.MON ;

mon.show();

注意 枚举项要放在第一行,枚举类可以有抽象方法,但是枚举项必须重写该方法

-----------------------------------------------------------------------------

枚举类的常见方法

ordinal() 返回枚举常量的序数 (枚举项都是有编号的)

compareTo() 枚举项比较的是编号

name() 获取枚举项的名称

toString()  也是打印名称,

valueOf Week mon = Week.value(Week.class,"MON");

System.out.println(mon);通过字节码文件

-------------------------------------------------------------------------------

JDK7的新特性

二进制字面量

数字字面量出现下划线

switch 语句可以用字符串

泛型简化,菱形泛型

异常的多个catch合并,每个异常就用或|

try with resources语句(自动关闭流)

-----------------------------------------------------------------------------

JDK1.8 接口中可以书写具有方法体的方法。如果不是静态方法 必须要用default修饰

用default修饰的就要采用实现类调用该方法,而静态方法可以接口名直接调用

局部内部类:

你可能感兴趣的:(Java基础笔记总结(19)-反射,枚举类 JDK1.7 1.8 新特性)