java面試——反射與泛型

来源:https://www.cnblogs.com/peixinyu/archive/2022/05/19/16290161.html
-Advertisement-
Play Games

一、反射 《java核心技術》 官方套話:能夠分析類能力的程式成為反射。 又通過網上搜索有這句話:反射指程式可以訪問、檢測和修改它本身狀態或行為的一種能力。 反射是用來乾什麼的呢? “明明我自己能直接new一個對象,為什麼它要繞一個圈子,先拿到Class對象,再調用Class對象的方法來創建對象呢, ...


一、反射

  《java核心技術》

  官方套話:能夠分析類能力的程式成為反射。

  又通過網上搜索有這句話:反射指程式可以訪問、檢測和修改它本身狀態或行為的一種能力。

 反射是用來乾什麼的呢?

  “明明我自己能直接new一個對象,為什麼它要繞一個圈子,先拿到Class對象,再調用Class對象的方法來創建對象呢,這不是多餘嗎?”

  說不出來,大體作用就是方便,以前只在JDBC用過,看了這邊文章後發現springMVC也用。。。。。。我學個寂寞

  https://www.cnblogs.com/Java3y/p/12320363.html 

 說說你對 Java 中反射的理解

  Java中的反射首先是能夠獲取到Java中要反射類的位元組碼,獲取位元組碼有三種方法,

  •   Class.forName(className)
  •   類名.class。
  •   obj.getClass()

  然後將位元組碼中的方法,變數,構造函數等映射成相應的Method、Filed、Constructor等類,這些類提供了豐富的方法可以被我們所使用。

1、反射機制

 反射是一種功能強大且複雜的機制,反射機制可以用來:

  • 在運行時分析類的能力
  • 在運行時查看對象
  • 實現通用的數組操作代碼
  • 利用Method對象,這個對象很像C++中的函數指針

   這個method對象找了很多資料,還是沒太搞明白

2、Class類

獲取Class類對象的三種方法:

  •   常用的有getClass()方法將返回一個Class類型的實例,getName()方法將返回類的名字。
  •   可以調用靜態方法forName()獲取類名對應的Class對象。
  •   如果T是任意java類型(或者void關鍵字),T.class將代表匹配的類對象。
1 package Reflect;
2 
3 public class Person {}

  Student和Teacher都是Person類的子類

package Reflect;

public class test {
    public static void main(String[] args) throws ClassNotFoundException {
        Person student = new Student();
        Person teacher = new Teacher();
        Object obj=new Object();
        System.out.println(student.getClass());
        System.out.println(teacher.getClass());
        System.out.println(obj.getClass());
//        class Reflect.Student
//        class Reflect.Teacher
//        class java.lang.Object
        System.out.println(student.getClass().getName());
        System.out.println(teacher.getClass().getName());
        System.out.println(obj.getClass().getName());
//        Reflect.Student
//        Reflect.Teacher
//        java.lang.Object
        Class c1=Class.forName("Reflect.Person");
        System.out.println(c1);
//        class Reflect.Person
        Class c2= Person.class;
        System.out.println(c2);
//        class Reflect.Person
    Class c3=int.class;
    System.out.println(c3);
// int,註意,一個Class對象實際上表示的是一個類型,而這個類型未必一定是一種類,比如這裡的int不是類,但int.class是一個Class類型的對象
    }
}

  獲取類對象可以搭配newInstance動態的創建一個類的實例!(調用的是類的預設無參構造器,如果沒有會拋出異常)

3、檢查類的結構

  在java.lang.reflect包中有三個類FieldMethodConstructor分別用於描述類的域,方法,構造器。這三個類都有一個getName的方法,用來返回項目的名稱。

  常用的方法有:

        Field類:getType() :返回描述域所屬類型的Class對象

            getModifiers():返回一個整形數值,用不同的位開關描述public和static這樣的修飾符使用情況

        Method類:getReturnType():方法的返回類型

             getParameterTypes():參數的類型

        Constructors類:getParameterTypes():參數的類型

        Class類:getFileds(),getMethods()和getConstructors()返回類提供的public域,方法,構造器,其中包括超類的公有成員

            getDeclareFields(),getDeclareMethods(),getDeclareConstructors()將返回類中聲明的全部域,方法和構造器,其中包括私有和受保護,但不包括超類成員

package Reflect;

import sun.management.MethodInfo;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Scanner;

public class ClassConstruct {
public static void main(String[] args) {
String name;
if (args.length > 0){
name=args[0];
}else {
Scanner in = new Scanner(System.in);
System.out.println("輸入類名(eg:java.util.Date)");
name=in.next();
}

try {
Class c1=Class.forName(name);
Class superc1=c1.getSuperclass();//獲得父類的對象
String modifiers= Modifier.toString(c1.getModifiers());//返回一個整形數值,用不同的位開關描述public和static這樣的修飾符使用狀況
if (modifiers.length()>0){
System.out.print(modifiers+" ");
}
System.out.print("class:"+name);
if (superc1 !=null && superc1 !=Object.class ){
System.out.print(" extends "+superc1.getName());
}
System.out.print("\n{\n");
printConstructors(c1);//列印出c1的構造器
System.out.println();
printMethods(c1);//列印出c1的方法
System.out.println();
printFields(c1);//列印出c1的域
}catch (ClassNotFoundException e){
e.printStackTrace();
}
System.out.println("}");
System.exit(0);
}

/**
* 列印出c1類的全部構造器
* @param c1
*/
private static void printConstructors(Class c1) {
Constructor[] constructors=c1.getDeclaredConstructors();//返回類的全部構造器

for (Constructor c:constructors) {
String name=c.getName();
System.out.print(" ");
String modifiers=Modifier.toString(c.getModifiers());
if (modifiers.length()>0){
System.out.print(modifiers+" ");
}
System.out.print(name+" (");

//列印參數類型
Class[] paramTypes=c.getExceptionTypes();
for (int i=0;i<paramTypes.length;i++){
if (i>0){
System.out.print(paramTypes[i].getName());
}
}
System.out.print(" );");
}
}

/**
* 列印出c1類的全部方法
* @param c1
*/
private static void printMethods(Class c1) {
Method[] methods=c1.getDeclaredMethods();

for (Method m:methods){
Class retType=m.getReturnType();//方法的返回類型
String name=m.getName();//獲得方法名

System.out.print(" ");
//列印public或static,返回類型和方法名
String modifiers=Modifier.toString(m.getModifiers());
if (modifiers.length()>0){
System.out.print(modifiers+" ");
}
System.out.print(retType.getName()+" "+name+" (");
//列印參數類型
Class[] paramType=m.getParameterTypes();
for (int i = 0; i <paramType.length ; i++) {
if (i>0){
System.out.print(",");
}
System.out.print(paramType[i].getName());
}
System.out.println(");");
}
}

/**
* 列印出c1類的全部域
* @param c1
*/
private static void printFields(Class c1) {
Field[] fields=c1.getDeclaredFields();

for (Field f:fields) {
Class type=f.getType();//得到域的類型
String name=f.getName();
System.out.print(" ");
String modifiers=Modifier.toString(f.getModifiers());
if (modifiers.length()>0){
System.out.print(modifiers+" ");
}
System.out.println(type.getName()+ " "+name+" ;");
}
}
}

控制台輸入一個類:eg:java.lang.Double,輸出:

public final class:java.lang.Double extends java.lang.Number
{
   public java.lang.Double ( );   public java.lang.Double ( );
  public boolean equals (java.lang.Object);
  public static java.lang.String toString (double);
  public java.lang.String toString ();
  public int hashCode ();
  public static int hashCode (double);
  public static double min (double,double);
  public static double max (double,double);
  public static native long doubleToRawLongBits (double);
  public static long doubleToLongBits (double);
  public static native double longBitsToDouble (long);
  public volatile int compareTo (java.lang.Object);
  public int compareTo (java.lang.Double);
  public byte byteValue ();
  public short shortValue ();
  public int intValue ();
  public long longValue ();
  public float floatValue ();
  public double doubleValue ();
  public static java.lang.Double valueOf (java.lang.String);
  public static java.lang.Double valueOf (double);
  public static java.lang.String toHexString (double);
  public static int compare (double,double);
  public static boolean isNaN (double);
  public boolean isNaN ();
  public static boolean isFinite (double);
  public static boolean isInfinite (double);
  public boolean isInfinite ();
  public static double sum (double,double);
  public static double parseDouble (java.lang.String);

 public static final double POSITIVE_INFINITY ;
 public static final double NEGATIVE_INFINITY ;
 public static final double NaN ;
 public static final double MAX_VALUE ;
 public static final double MIN_NORMAL ;
 public static final double MIN_VALUE ;
 public static final int MAX_EXPONENT ;
 public static final int MIN_EXPONENT ;
 public static final int SIZE ;
 public static final int BYTES ;
 public static final java.lang.Class TYPE ;
 private final double value ;
 private static final long serialVersionUID ;
}

Process finished with exit code 0

 在運行時使用反射分析對象

  查看對象域的關鍵方法是Field類中的get方法,如果f是Field類型的對象,obj是某個包含f域的類的抽象,f.get(obj)將返回一個對象,其值為obj域的當前值。

public class Person {
    public String name;
    public int val;
    public Person(String name,int val){
        this.name=name;
        this.val=val;
    }
}
public class ReflectTest {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        Person person=new Person("Curry",1000);
        Class c1=person.getClass();
        Field f=c1.getDeclaredField("val");//獲取它對象的某個域
        Object v=f.get(person);//
        System.out.println(v);
      //1000 } }

  這裡Person類中如果域的訪問許可權是private,則將會出錯

Exception in thread "main" java.lang.IllegalAccessException: Class Reflect.ReflectTest can not access a member of class Reflect.Person with modifiers "private"
    at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
    at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
    at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
    at java.lang.reflect.Field.get(Field.java:390)
    at Reflect.ReflectTest.main(ReflectTest.java:10)

 

  get()方法只能得到可訪問域的值,除非擁有許可權,否則java的安全機制只允許查看任意對象有哪些域,而不允許讀取他們的值。

  反射機制的預設行為受限於java的訪問控制,然而如果一個java程式沒有受到安全管理器的控制,就可以覆蓋訪問控制。為了達成目的,需要調用Field,Method或Constructors對象的setAccessible()

public class ReflectTest {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        Person person=new Person("Curry",1000);
        Class c1=person.getClass();
        Field f=c1.getDeclaredField("val");
        f.setAccessible(true);
        Object v=f.get(person);
        System.out.println(v);
     //1000 } }

  發現現在可以訪問了

    f.set(person,1900); 設置新值           

4、反射機制的動態代理

  摘自於https://www.cnblogs.com/lzq198754/p/5780331.html

  

public interface Subject {
    public String say(String name, int age);
}

class RealSubject implements Subject {
    public String say(String name, int age) {
        return name + "  " + age;
    }
}
//如果想要完成動態代理,首先需要定義一個InvocationHandler介面的子類,已完成代理的具體操作。
class MyInvocationHandler implements InvocationHandler { private Object obj = null; public Object bind(Object obj) { this.obj = obj; return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object temp = method.invoke(this.obj, args); return temp; } }
public class ProxyTest {
    public static void main(String[] args) throws Exception {
        MyInvocationHandler demo = new MyInvocationHandler();
        Subject sub = (Subject) demo.bind(new RealSubject());
        String info = sub.say("Rollen", 20);
        System.out.println(info);
     //Rollen  20
} }

 

二、泛型

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 背景 如今的前端是一個涉獵領域很廣的職業。作為一名前端,我們不僅要開發管理系統、數據中台、還要應對年報開發、節日活動等場景。不僅要會增刪改查,編寫表單,還要具備開發動畫、H5 游戲等能力。能做出很 Cool 的動畫效果,也是一種前端特有的成就感。所以,我們從動畫的實現方法入手,瞭解瀏覽器的渲染,以及 ...
  • 索引:對象或數組的對應位置的名字 數組的索引就是 number 類型的 0,1,2,3... 對象的索引就是 string 類型的屬性名 數字索引簽名:通過定義介面用來約束數組 type numberIndex{ [index:number]:string } const testArray:num ...
  • 這幾天是Spring版本日,很多Spring工件都發佈了新版本, Spring Framework 6.0.0 發佈了第 4 個裡程碑版本,此版本包含所有針對 5.3.20 的修複補丁,以及特定於 6.0 分支的 39 項修複和改進。而今天Spring Boot 2.7.0和Spring Secur ...
  • Anaconda 是一個跨平臺的版本,通過命令行來管理安裝包。進行大規模數據處理、預測分析和科學計算。它包括近 200 個工具包,大數據處理需要用到的常見包有 NumPy 、 SciPy 、 pandas 、 IPython 、 Matplotlib 、 Scikit-learn 、statsmod ...
  • #Scanner對象 java.util.Scanner是java5的特征,可以通過Scanner類來獲取用戶的輸入。 基本語法: 通過Scanner類的next()與nextLine()方法獲取輸入的字元串,在讀取前一般需要使用hasNext()與hasNextLine()判斷是否還有輸入的數據。 ...
  • JSP:全拼寫:java Server pages:java 伺服器端頁面 可以理解為一個特殊的頁面:可以定義html代碼也可以定義java的代碼 定義:JSP是簡化Servlet編寫的一種技術,它將Java代碼和HTML語句混合在同一個文件中編寫,只對網頁中的要動態產生的內容採用Java代碼來編寫... ...
  • 卸載redis # 查詢redis進程 ps -ef | grep redis # 關閉進程 kill -9 6379 # 停止redis-cli redis-cli shutdown # 刪除local目錄下與redis相關的文件 rm -rf /usr/local/bin/redis-* 安裝r ...
  • 異常 異常定義 異常是運行過程中出現的錯誤 人為錯誤:填寫錯誤等 隨機錯誤:網路中斷、記憶體耗盡等 一個健壯的程式必須處理各種各樣的錯誤 Java的異常是class Object Throwable Error OutOfMemoryError Exception RuntimeException N ...
一周排行
    -Advertisement-
    Play Games
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...