Java基礎筆記總結(19)-反射,枚舉類 JDK1.7 1.8 新特性

反射

類的加載概述

程序要使用某個類,如果類還未加載到內(nèi)存中,系統(tǒng)會通過加載,連接,初始化來實現(xiàn)對這個類進行初始化

加載,將class文件讀入內(nèi)存,并創(chuàng)建一個Class對象。任何類被使用時系統(tǒng)都會創(chuàng)建一個Class對象

連接

驗證:是否有正確的內(nèi)部結構,并和其他類協(xié)調(diào)一致

準備 負責為類的靜態(tài)成員分配內(nèi)存,并且設置默認值

解析 將類的二進制數(shù)據(jù)符號引用替換為直接引用

加載時機

創(chuàng)建類的實例

訪問類的靜態(tài)變量,或者為靜態(tài)變量賦值

調(diào)用類的靜態(tài)方法

使用反射方式來強制創(chuàng)建某個類或接口對應的java.lang.Class對象

初始化某個子類

直接使用java.exe來運行某個主類

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

類加載器分類:負責將.class文件加載到內(nèi)存中,并為之生成對應的Class對象

類加載器分類:

Bootstrap ClassLoader 根類加載器 引導類加載器 java核心類的加載System String 在jdk下的jre中的rt.jar

Extension ClassLoader 擴展類加載器 負責jre擴展目錄下的jar包的加載,在JDK中JRT的lib目錄下的ext目錄加載

System ClassLoader 系統(tǒng)類加載器 負責在JVM啟動時候加載來自java命令的class文件,以及classpath環(huán)境變量所指定的jar包和類路徑

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

反射概述

JAVA反射機制就是在運行過程中,對任意一個類,都能知道這個類所有的屬性和方法

對于任意的一個對象,都能夠調(diào)用它的任意一個方法和屬性

這種動態(tài)獲取信息以及動態(tài)調(diào)用對象方法的方式成為JAVA的反射機制

想要解刨一個類,必須要獲取到該類的字節(jié)碼文件對象

而解刨使用的就是Class類中的方法,所以要獲取每一個字節(jié)碼文件對應的Class文件

三種方式

Object類的getClass()方法,判斷兩個對象是否是同一個字節(jié)碼文件

靜態(tài)對象class,鎖對象

Class類中的靜態(tài)方法,讀取配置文件

源文件階段? ? ? 字節(jié)碼文件? ? ? ? ? 創(chuàng)建配置文件

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

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

Class clazz = Person.class;

Class clazz = p.getClass();

讀取配置文件,只改配置文件就可以獲取不同的屬性和方法

字節(jié)碼文件 當作靜態(tài)方法鎖對象

判斷是否是同一個字節(jié)碼對象

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

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 {

//沒用反射,只在使用動態(tài)

// Juicer juicer = new Juicer();

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

// 用發(fā)射和配置文件

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()方法是使用該類無參數(shù)的構造方法創(chuàng)建對象,一個類沒有無參數(shù)構造函數(shù),不能使用該方法,但是可以調(diào)用Class類的getConstructor()創(chuàng)建

獲取有參構造創(chuàng)建對象

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<Integer> 中添加一個字符串對象

ArrayList<Integer> list = new ArrayList<>();

list.add(11);

//泛型只在編譯器有效,在運行期會被擦除掉

// list.add("abc");

Class clazz = Class.forName("java.util.ArrayList"); //獲取字節(jié)碼對象

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{

// 獲取字節(jié)碼對象

Class clazz = obj.getClass();

// 暴力反射獲取字段

Field f = clazz.getDeclaredField(propertyName);

f.setAccessible(true);

f.set(obj, value);

}

}

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

1、xxx.properties獲取屬性類

2、利用反射獲取相關屬性,并運行方法

-------------------------------------------------------------------------------------反射的動態(tài)代理

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");

// 執(zhí)行被代理的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();

//動態(tài)代理

// 本來自己要做的請別人做,被請的人就是代理對象

// 在程序運行過程中產(chǎn)生這個對象,而程序運行過程中產(chǎn)生的對象就是我們剛才反射講解的內(nèi)容,所以動態(tài)代理就是通過反射生成一個代理

// Proxy 和 InvocationHandler接口,通過類和接口可以生成動態(tài)代理對象

MyInvocationHandler m = new MyInvocationHandler(ui);

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

u.add();

u.delete();

}

}

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

末班模式

就是定義一個算法的骨架,將具體的算法延遲到子類實現(xiàn),抽象類不希望被重寫的方法用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();

}

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

第一種 創(chuàng)建Enum類,直接寫入對象就可以實現(xiàn)

第二種 public enum Week2{

MON("")

private String name;

private Week2(String name){

this.name = name;

}

}

//可以寫入get set方法

測試 Week mon = Week.MON ;

第三種是寫入方法,用匿名實現(xiàn)子類方法

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() 返回枚舉常量的序數(shù) (枚舉項都是有編號的)

compareTo() 枚舉項比較的是編號

name() 獲取枚舉項的名稱

toString()? 也是打印名稱,

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

System.out.println(mon);通過字節(jié)碼文件

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

JDK7的新特性

二進制字面量

數(shù)字字面量出現(xiàn)下劃線

switch 語句可以用字符串

泛型簡化,菱形泛型

異常的多個catch合并,每個異常就用或|

try with resources語句(自動關閉流)

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

JDK1.8 接口中可以書寫具有方法體的方法。如果不是靜態(tài)方法 必須要用default修飾

用default修飾的就要采用實現(xiàn)類調(diào)用該方法,而靜態(tài)方法可以接口名直接調(diào)用

局部內(nèi)部類:

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容