**
反射的原理,Class.forName和ClassLoader區別,反射創建類實例的三種方式
Java在編譯的時候生成了一個 .class文件,反射就是通過尋找該文件裏的字節碼找到對應的類、方法、屬性。
Class.forName和ClassLoader區別在於前者加載類需要初始化後者不會只是將其加載到了jvm虛擬機中
public class testReflex {
public static void main(String args[]){
Person p1=new Person("小明" ,20,'男' );
Person p2=new Person("小紅",22,'女');
//第一種getClass()
Class class1=p1.getClass();
System. out.println(p1.getClass().getName());
try {
Field f=p1.getClass().getDeclaredField("name");
f.setAccessible(true);
f.set(p1, "阿狗");
System. out.println(p1.getName());
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Class class2 = p2.getClass();
System. out.println(class1 == class2 );//true
//第二種利用class屬性
Class class3=Person.class;
System. out.println(class1 == class3 );//true
Class class4=null;
try {
//第三種forName()
class4=Class.forName("test.Person");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(class4==class1);//true
}
}
**
**
final的用途
作用於變量若變量爲基本類型則不可修改,若變量爲引用則可以改變其指向的內容不能改變其指向(即地址不能改地址上存的值能改)
作用於參數與變量一致
作用於方法把方法鎖定,以防任何繼承類修改它的含義,即該方法不會被繼承的類覆蓋只能被繼承
作用於類該類不可被繼承
**
**
Jdk動態代理
jdk動態代理利用反射的機制不過只能代理接口委託類必須實現某個或者某些接口
接口類
package test;
public interface People{
public void sayHello();
}
實現類
package test;
public class Chinese implements People {
@Override
public void sayHello(){
System.out.println("Chinese say hello");
}
}
代理實現類
package test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class PeopleInvocationHandler implements InvocationHandler {
private Object people;
PeopleInvocationHandler(Object people){
this.people=people;
}
@Override
public Object invoke(Object proxy,Method method,Object args[])
throws Throwable{
//委託給sun.reflect.MethodAccessor來處理反射
Object invoke=method.invoke(people, args);
System.out.println("---end---");
return invoke;
}
}
測試類
package test;
import java.lang.reflect.Proxy;
public class testproxy {
public static void main(String args[]){
//子類向上轉型
People chinese=new Chinese();
PeopleInvocationHandler invohandler=new PeopleInvocationHandler(chinese);
//只能傳接口
People proxy= (People)Proxy.newProxyInstance(chinese.getClass().getClassLoader(),chinese.getClass().getInterfaces(),invohandler);
proxy.sayHello();
}
}
Cglib動態代理本質也是通過反射不過是利用繼承關係,利用asm在運行時動態生成委託類的子類,從而實現對委託類的代理。因此不依賴接口。所以不能代理final修飾的類
測試類
package test;
public class cglibchinese {
public void sayHello(){
System.out.println("Chinese say hello");
}
public void saysb(){
System.out.println("Chinese say hello sb");
}
}
代理生成類
package test;
import java.lang.reflect.Method;
import java.lang.Object;
import org.springframework.cglib.proxy.*;//用了spring-core-4.xx以上的版本
public class ChineseProxy implements MethodInterceptor{
@Override
public Object intercept(Object object,Method method,Object[] args,MethodProxy methodProxy) throws Throwable{
Object intercept=methodProxy.invokeSuper(object,args);
System.out.println("spcs");
return intercept;
}
}
代理測試類
package test;
import org.springframework.cglib.proxy.*;
public class testcglib {
public static void main(String args[]){
ChineseProxy chineseproxy=new ChineseProxy();
Enhancer enhancer=new Enhancer();
//enhancer.setSuperclass(Chinese.class);
enhancer.setSuperclass(cglibchinese.class);
enhancer.setCallback(chineseproxy);
//People proxy=(People)enhancer.create();代理接口利用向上轉型
cglibchinese proxy=(cglibchinese)enhancer.create();
proxy.sayHello();
}
}
**
**
在父類中爲子類自動完成所有的 hashcode 和 equals 實現
優點可以添加自定義邏輯,且不必調用超類的實現。
缺點容易出問題尤其是在子類覆蓋equals方法沒覆蓋hashcode時可能降低散列表性能,或者相同對象不同hashcode
**