面试30K开发岗被美女HR问到Java注解与反射,她是新来的吧?

Posted 益达学长

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试30K开发岗被美女HR问到Java注解与反射,她是新来的吧?相关的知识,希望对你有一定的参考价值。

注解(Annotation)简介

注解(Annotation)是从JDK5.0引入的新技术

Annotation作用:注解(Annotation)可以被其他程序如编译器等读取

Annotation格式:@“注释名”,当然可以添加一些参数值(形如:@Retention(RetentionPolicy.RUNTIME)

它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

Annotation注解可以通过反射去读取

注解的定义

内置注解

@Override 定义在java.lang.Override中,此注释只适用于修辞方法,表示声明一个方法打算重写超类中的另一个方法。

@Deprecated定义在java.lang.Deprecated中,此注释只适用于修辞方法,属性,类,表示不支持使用这样的元素

@SupperWarnings定义在java.lang.SupperWarnings中,用来抑制编译告警时的警告信息,需要添加一个参数才能正确使用

元注解

元注解的作用就是负责注解其他注解,java定义了4个标准的meta-annotation类型:@Target/@Retention/@Document/@Inherited

元注解中重点为@Target@Retention

@Target:用于描述注解的作用范围(比如作用在某个类或某个方法)

@Retention:描述注解的生命周期,对于反射就是可以在什么时候获取该注解(SOURCE<CLASS<RUNTIME

自定义注解

使用@interface可以自定义注解。

@interface 注解名{
		//自定义的注解内容
    //如果参数只有一个值,建议写value
    String value();
}

例子

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public class TestAnnotationDemo3 {

    //测试自定义注解
    @MyAnnotation2("qifei")
    @MyAnnotation(name = "wuhu", id = 10)
    public void test(){
        System.out.println("test");
    }
}

@Target(value = {ElementType.TYPE,ElementType.METHOD})  //作用于 方法和类
@Retention(RetentionPolicy.RUNTIME)    //作用于 运行时
@interface MyAnnotation{
    //定义参数
    String[] name() default ""; //参数默认为空,参数名为name
    int id();
}

@Target(value = {ElementType.TYPE,ElementType.METHOD})  //作用于 方法和类
@Retention(RetentionPolicy.RUNTIME)    //作用于 运行时
@interface MyAnnotation2{
    //如果参数只有一个值,建议写value
    String value();
}

反射(Reflection)机制

Java反射(Reflection)是Java非常重要的动态特性,通过使用反射我们不仅可以获取到任何类的成员方法、成员变量、构造方法等信息,还可以动态创建Java类实例、调用任意的类方法、修改任意的类成员变量值等。注解和反射是各种java web框架的底层实现机制与灵魂。

Class类

反射首先要用到的就是Class类,Class类是一个描述类的类,但是Class本身也是一个类,一个在内存中加载的类在JVM中只会有一个对应的Class的实例话对象,通过Class可以完整的得到一个类中所有被加载的结构。Class类就是反射的根源

获取Class类实例

1、已知具体的类,通过类的class属性获取

Class c = Object.class;

2、已知某个类的实例,通过调用getClass()方法获取class对象

Person person = new Person();
Class c = person.getClass();

3、已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取class对象

Class c = Class.forName("com.reflection.demmo");

4、基本内置类型的包装类的Type属性获取class对象

Class c = Integer.TYPE;

例子:

//测试class类的创建方式
public class ReflactionDemo02 {

    public static void main(String[] args) throws ClassNotFoundException {
        Person student = new Student();
        System.out.println("这个人是:" + student.name);

        //获取Student类的class实例对象
        //1、通过getClass() 获得
        Class c1 = student.getClass();
        System.out.println(c1.hashCode());

        //2、通过Class类的forName() 获得
        Class c2 = Class.forName("com.reflaction.Student");
        System.out.println(c2.hashCode());

        //3、通过student类的class属性获得
        Class c3 = Student.class;
        System.out.println(c3.hashCode());

        //4、基本内置类型的包装类的Type属性
        Class c4 = Integer.TYPE;
        System.out.println(c4.hashCode());

        //获得父类类型
        Class c5 = c1.getSuperclass();
        System.out.println(c5);

    }

}

class Person{
    String name;

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\\'' +
                '}';
    }
}

class Student extends Person{
    public Student(){
        this.name = "学生";
    }
}

class Teacher extends Person{
    public Teacher(){
        this.name = "老师";
    }
}

这个人是:学生
1627674070
1627674070
1627674070
1360875712
class com.reflaction.Person

具有Class实例对象的数据类型

//所有类型的class对象
public class ReflactionDemo03 {
    public static void main(String[] args) {
        Class c1 = Object.class;    //类
        Class c2 = Runnable.class;  //接口
        Class c3 = String[].class;  //一维数组
        Class c4 = String[][].class;    //二维数组
        Class c5 = Override.class;  //注解
        Class c6 = ElementType.class;   //枚举
        Class c7 = Integer.class;   //基本数据类型包装类
        Class c8 = void.class;  //void
        Class c9 = Class.class; //Class

        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);
        System.out.println(c4);
        System.out.println(c5);
        System.out.println(c6);
        System.out.println(c7);
        System.out.println(c8);
        System.out.println(c9);

    }
}
class java.lang.Object
interface java.lang.Runnable
class [Ljava.lang.String;
class [[Ljava.lang.String;
interface java.lang.Override
class java.lang.annotation.ElementType
class java.lang.Integer
void
class java.lang.Class

反射获取类运行时的完整结构

Field()

Field[] fields = c1.getFields();    //getFields 只能找到pubilc属性
        fields = c1.getDeclaredFields();    //getDeclaredFields 可以找到所有属性
        for (Field field : fields) {
            System.out.println(field);
        }

Method()

getMethods()获得本类和继承类的所有public方法

getDeclaredMethods()获取本类的所有方法

getMethod("方法名", 参数类型.class)获得指定的方法

//获得本类和继承类的所有public方法
        Method[] methods = c1.getMethods(); 
        for (Method method : methods
             ) {
            System.out.println("getMethods(): " + method);
        }

//获取本类的所有方法
        methods = c1.getDeclaredMethods();  
        for (Method method : methods
             ) {
            System.out.println("getDeclaredMethods(): " + method);
        }
 //获得指定的方法
        Method setName = c1.getMethod("setName", String.class);
        Method getName = c1.getMethod("getName");

        System.out.println(setName);
        System.out.println(getName);

Constructor()

//获取所有的构造器
        Constructor[] constructors = c1.getConstructors();      //获取本类和父类的所有构造方法
        for (Constructor constructor : constructors
             ) {
            System.out.println(constructor);
        }
        System.out.println("=====================================");
        constructors = c1.getDeclaredConstructors();        //获取本类所有构造方法

        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }

        System.out.println("=====================================");
        //获取指定的构造器
        Constructor constructor = c1.getConstructor(String.class, int.class, int.class);
        System.out.println(constructor);

反射类构造器获得实例化对象

  1. 反射获得User类的class对象Class.forName()
  2. 调用有参或无参构造方法实例化对象class.newInstance()
public static void main(String[] args) throws Exception{
        //反射获得User类的class对象
        Class c1 = Class.forName("com.reflaction.User");
        User user = (User) c1.newInstance();            //调用无参构造实例化对象
        System.out.println(user);

        //获得有参构造方法
        Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);

        //通过构造器获得实例话对象
        User ago = (User) constructor.newInstance("ago", 18, 1);    //有参构造获得实例化对象
        System.out.println(ago);

    }

User{name='null', age=0, id=0}
User{name='ago', age=18, id=1}

反射获取调用普通方法

方式1: 反射获取目标类的class对象(Class.forName()) ==> 获取有参构造器(class.getDeclaredConstructor()) ==> 获取目标类实例化对象(constructor1.newInstance(param1, param2, param3 ,…)) ==> 调用方法(实例化对象.Method())

Class c2 = Class.forName("com.reflaction.User");
        Constructor constructor1 = c2.getDeclaredConstructor(String.class, int.class, int.class);
        User zh1z3ven = (User) constructor1.newInstance("zh1z3ven", 20, 2);
        System.out.println(zh1z3ven.getAge());
        System.out.println(zh1z3ven.getName());
				zh1z3ven.setId(20);
        System.out.println(zh1z3ven.getId());

方式2: 反射获取目标类class对象(Class.forName()) ==> 获取指定方法(class.getMethod(“方法名”, 参数)) ==> 激活执行方法(.invoke(目标对象, 参数))

Class c2 = Class.forName("com.reflaction.User");

        User user2 = (User) c2.newInstance();
        Method setName = c2.getMethod("setName", String.class);
        setName.invoke(user2, "kfei");
        System.out.println(user2.getName());

反射操作属性

  1. 获取class对象
  2. class.getDeclaredField("属性名") 获取属性
  3. .set() 方法设置属性
  4. 若为private修饰,出现无权限操作异常,可用.setAccessible(true) 关闭安全检测,获取操作权限
Class c3 = Class.forName("com.reflaction.User");
        User user4 = (User) c3.newInstance();

        Field name = c3.getDeclaredField("name");

        name.setAccessible(true);
        name.set(user4 ,"zgo");
        System.out.println(user4.getName());

Invoke(Object obj, Obj… args)

Object对应原方法返回值,若无返回值,返回null

若原方法为静态方法,形参Object obj可为null

若原方法形参列表为空,Obj… args可为null

若原方法声明为private,在调用invoke()前,显示调用方法对象的.setAccessible(true)方法,关闭安全检测,获取访问权限

反射调用Runtime()

import org.apache.commons.io.IOUtils;

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class RuntimeExecDemo {
    public static void main(String[] args) throws Exception{

        String command = "ifconfig";
        Class c = Class.forName("java.lang.Runtime");   //获取Runtime类的class对象
        Constructor constructor = c.getDeclaredConstructor();   //获取构造器
        constructor.setAccessible(true);   //关闭安全检测,暴力反射
        Object runtime = constructor.newInstance();     //构造runtime对象
        Method exec = c.getMethod("exec", String.class);    //获取exec方法
        Process process = (Process) exec.invoke(runtime, command);  //激活执行exec

        //获取命令回显结果
        InputStream inputStream = process.getInputStream();     //获取process输入流中输出的数据
        String ifconfig = IOUtils.toString(inputStream, "GBK");     //字节流转字符流
        System.out.println(ifconfig);      //打印结果

    }
}

反射操作泛型

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

public class TestFanXingDemo {

    public void test01(Map<String, User> map, List<User> list){
        System.out.println("test01");
    }

    public Map<String, User> test02(){
        System.out.println("test02");
        return null;
    }

    public static void main(String[] args) throws NoSuchMethodException {

        Method method = TestFanXingDemo.class.getMethod("test01", Map.class, List.class);
        method.setAccessible(true);     //关闭安全检测,暴力反射
        Type[] genericParameterTypes = method.getGenericParameterTypes();   //获得泛型的参数类型

        for (Type genericParameterType : genericParameterTypes) {
            System.out.println("#genericParameterType: " + genericParameterType);   //遍历泛型类型

            if (genericParameterType instanceof ParameterizedType){     //判断泛型参数类型是否是参数化类型
                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();   //获得真实参数信息

                //循环遍历参数
                for (Type actualTypeArgument : actualTypeArguments) {       
                    System.out.println(actualTypeArgument);
                }
            }
        }
    }

}

反射操作注解

ORM = Object Relationship Mapping ==> 对象关系映射

类和表对应,类的属性和表的字段对应,对象和记录对应

利用注解和反射完成类和表的结构的映射关系

import java.lang.annotation.*;
import java.lang.reflect.Field;

public class TestDemo12 {

    //反射操作注解
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("com.reflaction.Student2");

        //通过反射获得全部注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }

        //获得注解的value值
        TableStudent tableStudent = (TableStudent) c1.getAnnotation(TableStudent.class);
        String value = tableStudent.value();//获取注解的value
        System.out.println(value);

        //获取指定类的注解value
        Field f = c1.getDeclaredField("name");
        FieldStudent annotation = f.getAnnotation(FieldStudent.class);
        System.out.println(annotation.columnName());
        System.out.println(annotation.type());
        System.out.println以上是关于面试30K开发岗被美女HR问到Java注解与反射,她是新来的吧?的主要内容,如果未能解决你的问题,请参考以下文章

程序员的奇葩面试:要价 25K,HR 却给 30K

面试一个30K的岗位,从JVM的根源问到了架构思想

面试最怕问到的 Java 虚拟机,是通往高级 Java 开发的必经之路

HR面试常问到的问题

面试腾讯高级开发岗被问:k8s之Service详解-Service使用

面试拼多多 Java 岗被刷了三次,在家闭关刷题66天,卷土重来,终获offer