java面试——反射与泛型

一、反射

  《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); 设置新值   

Method中的invoke方法

复制代码
import org.junit.Test;

import java.lang.reflect.Method;

public class InvokeTest {
    public void test(String[] arg) {
        for (String string : arg) {
            System.out.println("zp is " + string);
        }
    }

    @Test
    public void invokeDemo() throws Exception {
        //获取字节码对象,这里要填好你对应对象的包的路径
        Class<InvokeTest> clazz = (Class<InvokeTest>) Class.forName("InvokeTest");
        //形式一:获取一个对象
//        Constructor con =  clazz.getConstructor();
//        InvokeTest m = (InvokeTest) con.newInstance();
        //形式二:直接new对象,实际上不是框架的话,自己写代码直接指定某个对象创建并调用也可以
        InvokeTest m = new InvokeTest();
        String[] s = new String[]{"handsome", "smart"};
        //获取Method对象
        Method method = clazz.getMethod("test", String[].class);
        //调用invoke方法来调用
        method.invoke(m, (Object) s);
    }
}

//zp is handsome
//zp is smart


复制代码

invoke的意思上就有调用的意思,也就是说我们可以通过反射包下的Method类调用invoke方法,调用我们所提供的方法以及调用方法的参数来完成动态调用。

也就是根据你给的对象/实例,方法名,以及参数来调用。找了个“替身”来帮你调用方法。

        

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
} }
复制代码

 

二、泛型

 https://www.cnblogs.com/panjun-Donet/archive/2008/09/27/1300609.html

 类型擦除:

  https://www.cnblogs.com/wuqinglong/p/9456193.html

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

 

posted on   xy-pei  阅读(279)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示