Java反射
沒有反射就沒有任何EE框架!
對象的正向處理是什麼呢?就是根據類產生對象,舉一個簡單的日期類爲例
Date date=new Date();
System.out.println(date);
反射:對象的反向處理。根據對象倒推類的組成。
反射的核心處理在於Object類的方法:---取得類的class對象
查看Object類方法:[Alt+7]
查看其源碼:
@return The {@code Class} object that represents the runtime
* class of this object.
* @jls 15.8.2 Class Literals
*/
@HotSpotIntrinsicCandidate
public final native Class<?> getClass();
public final native Class<?> getClass();也就是返回一個運行時產生的對象
class類描述各個類的組成(包括構造方法,普通方法,普通屬性)
1取得class對象
任何一個類的class對象由JVM加載類後產生,該對象在JVM中全局唯一,用戶只能調用指定方法來取得該對象
a.任何類的對象可以通過調用Object類的getClass()取得(要反射的)該類的Class對象
[類對象.getClass()]
Date date=new Date();
System.out.println(date.getClass());
b.[類名稱.Class]可以根據某個具體類來取得其Class對象
System.out.println(Date.class);
c.調用Class類的靜態方法+Class.forName(String className)傳入類的全名稱來取得類的Class對象
System.out.println(Class.forName("java.util.Date"));
輸出都爲:class java.util.Date
2取得一個類的Class對象後通過反射來實例化對象
在Class類中有如下方法:
Java9之後不推薦使用newInstance方法已經被禁用,選擇其他方法
class.getDeclaredConstructor().newInstance()
1.class.newInstance():會直接調用該類的無參構造函數進行實例化
2.class.getDeclaredConstructor().newInstance()
getDeclaredConstructor()方法會根據他的參數對該類的構造函數進行搜索並返回對應的構造函數,沒有參數就返回該類的無參構造函數,然後再通過newInstance進行實例化。
舉例:通過反射取得Date類的實例化對象
package se.SE.practice;
import java.lang.reflect.InvocationTargetException;
import java.text.DateFormat;
import java.util.Date;
public class reflect {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
// 取得class對象
Class<Date> myclass=(Class<Date>)Class.forName("java.util.Date");
// 通過反射取得Date類實例化對象
Date date=myclass.getDeclaredConstructor().newInstance();
System.out.println(date);
}
}
輸出結果:
3優化工廠模式
工廠模式中每增加一個產品,就增加一條if else語句
比如:假設有水果加工工廠Factory0,子類實現水果接口(interface IFruit),有蘋果Apple類,桔子Orange類爲子類
現在需要增加一個子類Pear,需要在Factory0類中增加:
else if(className.equals("pear")){
return new Pear;
}
interface IFruit{
void eat();
}
class Apple implements IFruit{
@Override
public void eat() {
System.out.printf("eat an apple");
}
}
class Orange implements IFruit{
@Override
public void eat() {
System.out.println("eat an orange");
}
}
class Pear implements IFruit{
@Override
public void eat() {
System.out.println("eat an pear");
}
}
class Factory0{
private Factory0(){}
public static IFruit getInstance(String className){//利用getInstance來實例化對象
if(className.equals("apple")){
return new Apple();
}else if(className.equals("orange")){
return new Orange();
}else if(className.equals("pear")){
return new Pear;
}
return null;
}
}
public class Factory {
public static void main(String[] args) {
IFruit iFruit=Factory0.getInstance("apple");
iFruit.eat();
}
}
結果:eat an apple
那麼反射就可以解決工廠模式的這一弊端----反射修改工廠方法
class Factory0{
private Factory0(){}
public static IFruit getInstance(String className){
IFruit iFruit=null;
try {
//取得類名爲className類的class對象
Class<?> myclass =Class.forName(className);
//通過反射,來對象的實例化
iFruit= (IFruit) myclass.getDeclaredConstructor().newInstance();
}catch (Exception e){
e.printStackTrace();
}
return iFruit;
}
}
public class Factory {
public static void main(String[] args) {
IFruit iFruit=Factory0.getInstance("se.SE.practice.Pear");
iFruit.eat();
}
}
完整代碼:
package se.SE.practice;
interface IFruit{
void eat();
}
class Apple implements IFruit{
@Override
public void eat() {
System.out.printf("eat an apple");
}
}
class Orange implements IFruit{
@Override
public void eat() {
System.out.println("eat an orange");
}
}
class Pear implements IFruit{
@Override
public void eat() {
System.out.println("eat an pear");
}
}
class Factory0{
private Factory0(){}
public static IFruit getInstance(String className){//利用getInstance來實例化對象
IFruit iFruit=null;
try{
//取得class類
Class<?> myclass=Class.forName(className);
//通過反射實例化對象
iFruit=(IFruit)myclass.getDeclaredConstructor().getInstance();
}catch(Exception e){
e.printStackTrace();
}
return iFruit;
}
}
class Factory0{
private Factory0(){}
public static IFruit getInstance(String className){
IFruit iFruit=null;
try {
//取得類名爲className類的class對象
Class<?> myclass =Class.forName(className);
//通過反射,來對象的實例化
iFruit= (IFruit) myclass.getDeclaredConstructor().newInstance();
}catch (Exception e){
e.printStackTrace();
}
return iFruit;
}
}
public class Factory {
public static void main(String[] args) {
IFruit iFruit=Factory0.getInstance("se.SE.practice.Pear");
iFruit.eat();
}
}
輸出:eat an pear
2反射與類操作
2.1通過反射取得父類與父接口信息:
a.取得類的包名稱:
public Package getPackage()
方法一:
Class<?> myclass=Date.class;//取得Date類的class對象
System.out.println(myclass.getPackage().getName);//取得myclass對象的包名稱
輸出:package java.util
2.2取得父類的Class對象(不理解通配符可先了解泛型(通配符)相關知識點)
---父類爲單繼承,只可能有一個
public native Class<? super T> getSuperClass();//泛型下限通配符,取得父類對象
2.3實現的父接口
---父接口爲多繼承,可能有多個
public Class<?>[] getInterfaces();
foreach循環語法:
第一個表達式是聲明一個變量去接受每次循環得到的元素
第二個表達式是需要遍歷的數組或集合 定義的變量類型必須跟數組的類型一致(表達式一的數據類型必須與表達式二數據類型一致)
for(Class classs:classes){
System.out.println(classs.getName());
}
代碼實現:
package se.SE.practice;
class Person{}//定義父類Person()
interface INews{}
interface IMessage{}
class Student extends Person implements INews,IMessage{}
//定義子類Student繼承父類Person實現INews和IMessage接口
public class reflect {
public static void main(String[] args) {
// 取得Student類的class對象
Class<?> myclass=Student.class;
// 取得父類信息
System.out.println(myclass.getSuperclass().getName());
// 取得父接口
Class<?>[] classes=myclass.getInterfaces();
for(Class classs:classes){
System.out.println(classs.getName());
}
}
}
結果: