1鬓催、動(dòng)態(tài)語(yǔ)言和靜態(tài)語(yǔ)言
- 動(dòng)態(tài)語(yǔ)言
1肺素、c#,php深浮,python压怠,JavaScript等!都屬于動(dòng)態(tài)語(yǔ)言飞苇。
2菌瘫、概念:在程序運(yùn)行中可以改變程序的結(jié)構(gòu)和邏輯。 - 靜態(tài)語(yǔ)言
1布卡、c++雨让,java等!屬于靜態(tài)語(yǔ)言忿等。
2栖忠、概念:在程序運(yùn)行時(shí)就不能改了,只能重新運(yùn)行贸街。 -
圖片介紹靜態(tài)vs動(dòng)態(tài)語(yǔ)言.png
2庵寞、反射
- Reflection(反射)是Java被視為動(dòng)態(tài)語(yǔ)言的關(guān)鍵
- 反射機(jī)制允許程序執(zhí)行期借助于Reflection API取得任何類(lèi)的內(nèi)部信息并能直接操作任意對(duì)象的內(nèi)部屬性及方法
- 加載完類(lèi)之后,在堆內(nèi)存中會(huì)生成一個(gè)class對(duì)象(一個(gè)類(lèi)只有一個(gè)對(duì)象)薛匪,這個(gè)對(duì)象包含了完整的類(lèi)結(jié)構(gòu)信息捐川,通過(guò)對(duì)象可以看到類(lèi)的結(jié)構(gòu),這個(gè)對(duì)象就想一面鏡子一樣可以看到類(lèi)的結(jié)構(gòu)逸尖,所有我們形象的稱(chēng)之為:反射
- 通過(guò)下面的代碼中獲取hashcode可以看出一個(gè)類(lèi)只能生成一個(gè)對(duì)象
Class<?> aClass = Class.forName("com.tools.server.Reflection.Test04_反射");
Class<?> aClass1 = Class.forName("com.tools.server.Reflection.Test04_反射");
Class<?> aClass2 = Class.forName("com.tools.server.Reflection.Test04_反射");
System.out.println(aClass.hashCode());
System.out.println(aClass1.hashCode());
System.out.println(aClass2.hashCode());
打庸帕ぁ:
471910020
471910020
471910020
-
圖片介紹正常方式vs反射方式.png
3、Java反射機(jī)制提供的功能
- 在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類(lèi)
- 在運(yùn)行時(shí)構(gòu)造任意一個(gè)類(lèi)的對(duì)象
- 在運(yùn)行時(shí)判斷任意一個(gè)類(lèi)所擁有的成員變量和方法
- 在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的成員變量和方法
- 在運(yùn)行時(shí)獲取泛型信息
- 在運(yùn)行時(shí)處理注解
- 生成動(dòng)態(tài)代理
- .............
4娇跟、Java反射優(yōu)點(diǎn)和缺點(diǎn)
- 優(yōu)點(diǎn)
1岩齿、可以實(shí)現(xiàn)動(dòng)態(tài)創(chuàng)建對(duì)象和編譯 - 缺點(diǎn)
1、對(duì)性能有影響苞俘。
2盹沈、使用反射基本上是一種解釋操作,我們可以告訴JVM吃谣,我們希望做什么并且它滿足我們的要求乞封。
3、這種操作總是慢于 直接執(zhí)行相同的操作
4基协、反射出來(lái)的對(duì)象相比new出來(lái)的對(duì)象歌亲,相差十幾倍
5、反射相關(guān)的主要API
- java.lang.Class:代表一個(gè)類(lèi)
- java.lang.reflect.Method:代表類(lèi)的方法
- java.lang.reflect.Field:代表類(lèi)的成員變量
- java.lang.reflect.Constructor:代表類(lèi)的構(gòu)造器
- ................
6澜驮、Class類(lèi)(678910做為class了解)
- 對(duì)象照鏡子后可以得到的信息:某個(gè)類(lèi)的屬性陷揪、方法和構(gòu)造器、某個(gè)類(lèi)到底實(shí)現(xiàn)了哪些接口杂穷。 對(duì)于每個(gè)類(lèi)而言悍缠,JRE都為其保留一個(gè)不變的Class類(lèi)型的對(duì)象。 一個(gè)Class對(duì)象包含了特定某個(gè)結(jié)構(gòu)(class/interface/enum/annotation/primitive type/void/[])的有關(guān)信息耐量。
- Class本身也是一個(gè)類(lèi)
- Class對(duì)象只能由系統(tǒng)建立對(duì)象
- 一個(gè)加載的類(lèi)在JVM中只會(huì)有一個(gè)Class實(shí)例
- 一個(gè)Class對(duì)象對(duì)應(yīng)的是一個(gè)加載到JVM中的一個(gè).class文件
- 每個(gè)類(lèi)的實(shí)例都會(huì)記得自己是由哪個(gè)Class實(shí)例所生成
- 通過(guò)Class可以完整地得到一個(gè)類(lèi)中的所有被加載的構(gòu)造
- Class類(lèi)是Reflection的根源飞蚓,針對(duì)任何你想動(dòng)態(tài)加載、運(yùn)行的類(lèi)廊蜒,只能先獲得相應(yīng)的Class對(duì)象
-
Class類(lèi)的常用方法
- newInstance()方法本質(zhì)是調(diào)用了無(wú)參構(gòu)造器
a) 類(lèi)必須有一個(gè)無(wú)參數(shù)的構(gòu)造器
b) 類(lèi)的構(gòu)造器的訪問(wèn)權(quán)限需要足夠
- newInstance()方法本質(zhì)是調(diào)用了無(wú)參構(gòu)造器
- Class類(lèi)的幾種創(chuàng)建方式
//Class類(lèi)的創(chuàng)建方式
//方式1趴拧、將類(lèi)的路徑作為參數(shù)溅漾,可能拋出ClassNotFoundException
Class<?> aClass = Class.forName("com.tools.server.Reflection.User");
//方式2、最安全可靠著榴,性能高
Class<User> aClass2 = User.class;
//方式3添履、調(diào)用某個(gè)類(lèi)的實(shí)例的getClass()方法獲取
User user = new User(1,20,"whl");
Class<? extends User> aClass3 = user.getClass();
System.out.println(aClass.hashCode());
System.out.println(aClass2.hashCode());
System.out.println(aClass3.hashCode());
//打印結(jié)果:
// 531885035
// 531885035
// 531885035
- 所有類(lèi)型的Class
Class c1 = Object.class;//類(lèi)
Class c2 = Comparable.class;//接口
Class c3 = String[].class;//一維數(shù)組
Class c4 = int[][].class;//二維數(shù)組
Class c5 = void.class;//空類(lèi)型
Class c6 = Override.class;//注解
Class c7 = ElementType.class;//枚舉
Class c8 = Integer.class;//基本數(shù)據(jù)類(lèi)型
System.out.println("c1:"+c1); class java.lang.Object
System.out.println("c2:"+c2); interface java.lang.Comparable
System.out.println("c3:"+c3); class [Ljava.lang.String;
System.out.println("c4:"+c4); class [[I
System.out.println("c5:"+c5); void
System.out.println("c6:"+c6); interface java.lang.Override
System.out.println("c7:"+c7); class java.lang.annotation.ElementType
System.out.println("c8:"+c8); class java.lang.Integer
7、類(lèi)加載內(nèi)存分析
-
Java內(nèi)存分析
-
堆
a) 存放new的對(duì)象和數(shù)組
b) 可以被所有的線程共享脑又,不會(huì)存放別的對(duì)象引用(某個(gè)類(lèi)的實(shí)例暮胧,一個(gè)引用可以指向多個(gè)對(duì)象) -
棧
a) 存放基本變量類(lèi)型(會(huì)包含這個(gè)基本類(lèi)型的具體數(shù)值)
b) 引用對(duì)象的變量(會(huì)存放這個(gè)引用在堆中具體的位置) -
方法區(qū)
a) 可以被所有線程共享
b) 包含了所有的class和static變量 - 最后總結(jié),在java虛擬機(jī)中问麸,對(duì)象的引用是存在棧中的往衷,而對(duì)象是存放在堆中的
-
堆
-
類(lèi)的加載過(guò)程
-
觸發(fā)前景:當(dāng)程序主動(dòng)使用某個(gè)類(lèi)時(shí),如果該類(lèi)未被加載到內(nèi)存中严卖,則系統(tǒng)會(huì)通過(guò)如下三個(gè)步驟來(lái)對(duì)該類(lèi)進(jìn)行初始化席舍。
-
觸發(fā)前景:當(dāng)程序主動(dòng)使用某個(gè)類(lèi)時(shí),如果該類(lèi)未被加載到內(nèi)存中严卖,則系統(tǒng)會(huì)通過(guò)如下三個(gè)步驟來(lái)對(duì)該類(lèi)進(jìn)行初始化席舍。
-
類(lèi)的加載與ClassLoader的理解
- 代碼實(shí)現(xiàn)
public class Test06 {
public static void main(String[] args) {
A a = new A();
System.out.println(a.m);
/*
1.加載到內(nèi)存,會(huì)產(chǎn)生一個(gè)類(lèi)對(duì)應(yīng)Class對(duì)象
2.鏈接妄田,鏈接結(jié)束后 m = 0
3.初始化
<clinit>(){
System.out.println("靜態(tài)代碼塊初始化");
System.out.println("A方法無(wú)參構(gòu)造初始化");
m = 200;
m = 100;
}
*/
}
}
class A{
public A(){
System.out.println("A方法無(wú)參構(gòu)造初始化");
}
static{
System.out.println("靜態(tài)代碼塊初始化");
m = 200;
}
static int m = 100;
}
1俺亮、方法區(qū):先加載Test06類(lèi)的信息
2、方法區(qū):在加載A類(lèi)的信息
3疟呐、堆:生成Test06和A類(lèi)的class對(duì)象
4脚曾、棧:main方法初始化m=0,鏈接完畢启具,執(zhí)行new A()
5本讥、堆:new A():A類(lèi)的對(duì)象可以代替(3、)去方法區(qū)找A類(lèi)的信息
6鲁冯、方法區(qū):將類(lèi)的初始值和靜態(tài)代碼塊合并執(zhí)行拷沸,返回到棧
-
初始化過(guò)程
8、什么時(shí)候會(huì)發(fā)生類(lèi)初始化薯演?
-
類(lèi)的主動(dòng)引用(一定會(huì)發(fā)生類(lèi)的初始化)
- 當(dāng)虛擬機(jī)啟動(dòng)撞芍,先初始化main方法所在的類(lèi)
- new一個(gè)類(lèi)的對(duì)象
- 調(diào)用類(lèi)的靜態(tài)成員(除了final常量)和靜態(tài)方法
- 使用java.lang.reflect包的方法對(duì)類(lèi)進(jìn)行反射調(diào)用
- 當(dāng)初始化一個(gè)類(lèi),如果其父類(lèi)沒(méi)有被初始化跨扮,則先會(huì)初始化他的父類(lèi)
-
類(lèi)的被動(dòng)引用(不會(huì)發(fā)生類(lèi)的初始化)
- 當(dāng)訪問(wèn)一個(gè)靜態(tài)域時(shí)序无,只有真正聲明這個(gè)域的類(lèi)才會(huì)被初始化。如:當(dāng)通過(guò)子類(lèi)引用父類(lèi)的靜態(tài)變量衡创,不會(huì)導(dǎo)致子類(lèi)初始化
- 通過(guò)數(shù)組定義類(lèi)引用帝嗡,不會(huì)觸發(fā)此類(lèi)的初始化
- 引用常量不會(huì)觸發(fā)此類(lèi)的初始化(常量在鏈接階段就存入調(diào)用類(lèi)的常量池中了)
- 代碼測(cè)試
public class Test07_分析類(lèi)的初始化 {
static {
System.out.println("main類(lèi)被加載");
}
public static void main(String[] args) throws ClassNotFoundException {
//主動(dòng)引用
//1、他會(huì)先加載父類(lèi)璃氢,在加載子類(lèi)
Son son = new Son();
//2哟玷、反射會(huì)引發(fā)主動(dòng)引用:他使用java.lang.reflect包中的方法了
Class.forName("com.tools.server.Reflection.Son");
//3、調(diào)用類(lèi)的靜態(tài)方法
Son.method_s();
//被動(dòng)引用
//1一也、引用父類(lèi)的靜態(tài)變量或靜態(tài)方法:不會(huì)導(dǎo)致子類(lèi)初始化
System.out.println(Son.b);
Son.method_f();
//2巢寡、數(shù)組定義類(lèi)引用
Son[] array = new Son[9];
//3喉脖、引用常量
System.out.println(Son.A);
}
}
class Father{
static int b = 2;
static {
System.out.println("父類(lèi)被加載!");
}
public static void method_f(){
System.out.println("method_f讼渊!");
}
}
class Son extends Father{
static int m = 100;
static {
System.out.println("子類(lèi)被加載");
}
static final int A = 1;
public static void method_s(){
System.out.println("method_f动看!");
}
}
9尊剔、類(lèi)加載器
類(lèi)加載器的作用.png
//獲取系統(tǒng)類(lèi)加載器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
//獲取系統(tǒng)類(lèi)加載器的父類(lèi)加載器-->擴(kuò)展類(lèi)加載器
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent);
//獲取擴(kuò)展類(lèi)的父類(lèi)加載器-->根加載器(c/c++)
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);//引導(dǎo)類(lèi)加載器是java核心類(lèi)庫(kù)爪幻,無(wú)法直接獲取
//測(cè)試當(dāng)前類(lèi)是哪個(gè)加載器加載的
ClassLoader classLoader = Class.forName("com.tools.server.Reflection.Test08_類(lèi)加載器").getClassLoader();
System.out.println(classLoader);
//測(cè)試JDK內(nèi)置的類(lèi)是哪個(gè)加載器加載的
ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();
System.out.println(classLoader1);//引導(dǎo)類(lèi)加載器是java核心類(lèi)庫(kù),無(wú)法直接獲取
//如何獲得系統(tǒng)類(lèi)加載器可以加載的路徑
System.out.println(System.getProperty("java.class.path"));
- 面試官:你創(chuàng)建一個(gè)java.lang包在里面寫(xiě)些類(lèi)可以用嗎须误?
10挨稿、獲取類(lèi)運(yùn)行時(shí)結(jié)構(gòu)
Class aClass = Class.forName("com.tools.server.Reflection.User");
//獲取類(lèi)名
System.out.println(aClass.getSimpleName());//獲取類(lèi)名
System.out.println(aClass.getName());//獲取包名+類(lèi)名
/*打印:
User
com.tools.server.Reflection.User
*/
//獲取類(lèi)的屬性
Field[] fields = aClass.getFields();//獲取public屬性
Field[] fieldsall = aClass.getDeclaredFields();//獲取全部的屬性
System.out.println("-----------------------------------------------------");
for (int i = 0; i < fieldsall.length; i++) {
System.out.println(fieldsall[i]);
}
/*打泳┝ :
private int com.tools.server.Reflection.User.id
private int com.tools.server.Reflection.User.age
private java.lang.String com.tools.server.Reflection.User.name
*/
//獲取指定屬性
System.out.println("-----------------------------------------------------");
System.out.println(aClass.getDeclaredField("name"));
/*打幽谈省:
private java.lang.String com.tools.server.Reflection.User.name
*/
//獲取類(lèi)的方法
System.out.println("-----------------------------------------------------");
Method[] declaredMethodsall = aClass.getMethods();//獲取本類(lèi)和父類(lèi)所有的public方法
Method[] declaredMethods = aClass.getDeclaredMethods();
for (int i = 0; i < declaredMethods.length; i++) {
System.out.println(declaredMethods[i]);//獲取本類(lèi)的所有方法
}
/*打印:
public java.lang.String com.tools.server.Reflection.User.toString()
public java.lang.String com.tools.server.Reflection.User.getName()
public void com.tools.server.Reflection.User.setName(java.lang.String)
public int com.tools.server.Reflection.User.getId()
public void com.tools.server.Reflection.User.setId(int)
public int com.tools.server.Reflection.User.getAge()
public void com.tools.server.Reflection.User.setAge(int)
public void com.tools.server.Reflection.User.test()
*/
//獲取指定方法
System.out.println("-----------------------------------------------------");
System.out.println(aClass.getMethod("getAge", null));
System.out.println(aClass.getMethod("setAge", int.class));
/*打蛹酪:
public int com.tools.server.Reflection.User.getAge()
public void com.tools.server.Reflection.User.setAge(int)
*/
//獲取類(lèi)全部的構(gòu)造器
System.out.println("-----------------------------------------------------");
Constructor[] constructors = aClass.getConstructors();//獲取本類(lèi)構(gòu)造器的public方法
Constructor[] constructorsall = aClass.getDeclaredConstructors();//獲取本類(lèi)構(gòu)造器的全部方法
for (int i = 0; i < constructors.length; i++) {
System.out.println(constructors[i]);
}
/*打映艏摇:
public com.tools.server.Reflection.User(int,int,java.lang.String)
public com.tools.server.Reflection.User()
*/
//獲取指定的構(gòu)造器
System.out.println("-----------------------------------------------------");
Constructor declaredConstructor = aClass.getConstructor(int.class, int.class, String.class);
System.out.println(declaredConstructor);
/*打印:
public com.tools.server.Reflection.User(int,int,java.lang.String)
*/
11方淤、動(dòng)態(tài)創(chuàng)建對(duì)象執(zhí)行方法(通過(guò)反射創(chuàng)建對(duì)象)
-
調(diào)用指定方法
-
取消安全檢測(cè)setAccessible()方法
- 代碼測(cè)試
//獲取class對(duì)象
Class aClass = Class.forName("com.tools.server.Reflection.User");
//構(gòu)造一個(gè)對(duì)象
User user = (User) aClass.newInstance();//本質(zhì)是調(diào)用了無(wú)參構(gòu)造器钉赁,如果類(lèi)中沒(méi)有無(wú)參構(gòu)造器就會(huì)報(bào)錯(cuò)
System.out.println(user);
//通過(guò)構(gòu)造器構(gòu)造一個(gè)對(duì)象
Constructor constructor = aClass.getDeclaredConstructor(int.class,int.class,String.class);//參數(shù)順序不能變
User user2 = (User) constructor.newInstance( 001, 18,"wyz");//參數(shù)順序不能變,否則異常
System.out.println(user2);
//通過(guò)反射調(diào)用普通方法
User user3 = (User) aClass.newInstance();
System.out.println(user3.getName());
//通過(guò)反射獲取一個(gè)方法
Method setName = aClass.getDeclaredMethod("setName", String.class);
setName.invoke(user3,"whl");//invoke(激活)傳遞參數(shù)(對(duì)象携茂,值)
System.out.println(user3.getName());
//通過(guò)反射操作屬性
User user4 = (User) aClass.newInstance();
Field name = aClass.getDeclaredField("name");
name.setAccessible(true);//取消安全檢測(cè)你踩,不加他訪問(wèn)不了private方法
name.set(user4,"whl2");
System.out.println(user4.getName());
12、性能對(duì)比
- 正常方式
User user = new User();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
user.getName();
}
long endTime = System.currentTimeMillis();
System.out.println(endTime-startTime+" ms");//打踊淇唷:4ms
- 安全檢測(cè)
User user = new User();
Class<?> aClass = Class.forName("com.tools.server.Reflection.User");//class獲取對(duì)象
Method getName = aClass.getDeclaredMethod("getName", null);//獲取方法
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println(endTime-startTime+" ms");//打哟ぁ:47ms
- 關(guān)閉安全檢測(cè)
User user = new User();
Class<?> aClass = Class.forName("com.tools.server.Reflection.User");//class獲取對(duì)象
Method getName = aClass.getDeclaredMethod("getName", null);//獲取方法
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
getName.invoke(user,null);
getName.setAccessible(true);//關(guān)閉安全檢測(cè)
}
long endTime = System.currentTimeMillis();
System.out.println(endTime-startTime+" ms");//打印:17ms
-
總結(jié)
如果程序中反射用的多的話鸳谜,可以使用關(guān)閉安全檢測(cè)提升效率膝藕!