美文网首页
Java基础:类型信息

Java基础:类型信息

作者: 远方的橄榄树 | 来源:发表于2019-11-21 13:38 被阅读0次

1. Class对象

  • 每个类都有一个class对象,每当编写且编译了一个新类,就会产生一个Class对象(更恰当的说,是保存在一个同名的.class文件中)。
  • 所有的类都是在对其第一次使用时动态加载到JVM中的。当程序创建第一个对类的静态成员的引用时,就会加载这个类。这个证明构造器也是类的静态方法
public class Shop {
    public static void main(String[] args) {
        System.out.println("运行main()...");
        new Candy();

        System.out.println("获取Cookie的Class对象");
        try {
            // 获取Cookie类的Class对象
            Class<?> forName = Class.forName("clazz.Cookie");  // 包名+类名
            System.out.println(forName.getName()); 
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
class Candy {
    static {
        System.out.println("糖果");
    }
}
class Cookie {
    static {
        System.out.println("饼干");
    }
}
运行main()...
糖果
获取Cookie的Class对象
饼干
clazz.Cookie
  • 利用Class对象可以获取类型信息并创建实例。
package clazz;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class CateTest {

    private static void print(Class c) {
        System.out.println(c.getName()+ "是" + (c.isInterface() ? "接口" : "类"));
    }

    @SuppressWarnings("all")
    public static void main(String[] args) throws ClassNotFoundException,
            NoSuchMethodException, IllegalAccessException,
            InvocationTargetException, InstantiationException {
        Class<?> clazz = null;
        clazz = Class.forName("clazz.Cate");
        print(clazz);

        for (Class c : clazz.getInterfaces()) { // 获取接口Class
            print(c);
        }

        Class up = clazz.getSuperclass(); // 获取父类Class
        print(up);
        //有参构造器创建实例
        Constructor<Food> foodInit = up.getConstructor(String.class);
        Food food = foodInit.newInstance("food"); // 创建实例
        food.print();
        //无参构造器创建实例
        Constructor<Food> foodNoArgs = up.getConstructor();
        Food food1 = foodNoArgs.newInstance();
        food1.print();
    }
}

class Cate extends Food implements Rice, Drink, Meat {
    Cate(String name) {
        super(name);
    }
}

class Food {
    private String name;
    public Food() {
        this.name = "no food";
    }
    public Food(String name) { // 构造器一定到用public声明,否则calss对象无法获取
        this.name = name;
    }
    public void print() {
        System.out.println(name);
    }
}
interface Rice {}
interface Drink {}
interface Meat {}
clazz.Cate是类
clazz.Rice是接口
clazz.Drink是接口
clazz.Meat是接口
clazz.Food是类
food
no food
  • 类字面常量
    诸如Cate.classint.class即类字面常量。
    利用类字面常量可以优化上述代码(因为这种方式获取Class对象更简单、更安全)。
Class<Cate> clazz = Cate.class;
  • 使用.class语法获取Class对象不会引发初始化。

instanceof 关键字

  • instanceof 关键字用于检查一个对象是否是某个类的实例
        Integer i = 12;
        boolean b = i instanceof Integer; // true
//        boolean c = 12 instanceof Integer; // error
        
        Cate cate = new Cate("");
        boolean d = cate instanceof Food; // true
        boolean e = cate instanceof Rice; // true

        Object o = new Cate("o");
        boolean f = o instanceof Cate; // true

反射

a. 概念

java反射机制是在运行状态中,对于任意一个类都能知道这个类的所有属性和方法;对于一个对象,都能调用其任意一个属性和方法。这种动态获取类的信息或动态调用对象的方法叫做反射。

b. 通过反射获取构造方法并使用

public class ConstructorDemo {
    public static void main(String[] args) throws Exception {
        Class<Student> clazz = Student.class;

        System.out.println("获取所有共有构造器");
        Constructor[] constructors = clazz.getConstructors();
        for (Constructor c : constructors) {
            System.out.println(c);
        }

        System.out.println("获取所有构造器");
        constructors = clazz.getDeclaredConstructors();
        for (Constructor c : constructors) {
            System.out.println(c);
        }

        //获取无参构造器并调用
        Constructor<Student> conNoArgs = clazz.getConstructor();
        Student student = conNoArgs.newInstance();

        // 获取私有构造器并调用
        Constructor<Student> conPri = clazz.getDeclaredConstructor(Integer.class);
        conPri.setAccessible(true); // 暴力访问(忽略掉访问修饰符)
        Student student1 = conPri.newInstance(13);
    }
}

class Student {
    public Student() {
        System.out.println("student...");
    }
    public Student(String name) {
        System.out.println("student[name=" + name + "]");
    }
    public Student(String name, Integer age) {
        System.out.println("student[name=" + name + ", age=" + age + "]");
    }
    private Student(Integer age) {
        System.out.println("student[age=" + age + "]");
    }
}
获取所有共有构造器
public reflect.Student(java.lang.String,java.lang.Integer)
public reflect.Student(java.lang.String)
public reflect.Student()
获取所有构造器
private reflect.Student(java.lang.Integer)
public reflect.Student(java.lang.String,java.lang.Integer)
public reflect.Student(java.lang.String)
public reflect.Student()
student...
student[age=13]

c. 获取成员变量并调用

public class FieldDemo {
    public static void main(String[] args) throws Exception {
        Class<Teacher> clazz = Teacher.class;

        System.out.println("获取公共字段");
        Field[] fields = clazz.getFields();
        for (Field f : fields) {
            System.out.println(f);
        }

        System.out.println("获取所有字段");
        fields = clazz.getDeclaredFields();
        for (Field f : fields) {
            System.out.println(f);
        }

        System.out.println("获取公共字段并调用");
        Field name = clazz.getField("name");
        Constructor<Teacher> constructor = clazz.getConstructor();
        Teacher teacher = constructor.newInstance();
        name.set(teacher, "小明");
        System.out.println(teacher);

        System.out.println("获取非公共字段并调用");
        Field age = clazz.getDeclaredField("age");
        Field email = clazz.getDeclaredField("email");
        age.set(teacher, 23);
        email.setAccessible(true); //暴力反射,解除私有限定
        email.set(teacher, "1234567@qq.com");
        System.out.println(teacher);
    }
}

class Teacher {
    public String name;
    protected Integer age;
    boolean sex;
    private String email;

    public Teacher() {}

    @Override
    public String toString() {
        return "Teacher{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", email='" + email + '\'' +
                '}';
    }
}
获取公共字段
public java.lang.String reflect.Teacher.name
获取所有字段
public java.lang.String reflect.Teacher.name
protected java.lang.Integer reflect.Teacher.age
boolean reflect.Teacher.sex
private java.lang.String reflect.Teacher.email
获取公共字段并调用
Teacher{name='小明', age=null, sex=false, email='null'}
获取非公共字段并调用
Teacher{name='小明', age=23, sex=false, email='1234567@qq.com'}

d. 获取成员方法并调用

public class MethodDemo {
    public static void main(String[] args) throws Exception {
        Class<Food> clazz = Food.class;

        System.out.println("获取所有'共有'方法");
        Method[] methods = clazz.getMethods();
        for (Method m : methods) {
            System.out.println(m);
        }

        System.out.println("获取所有方法(除Object方法外的所有方法)");
        methods = clazz.getDeclaredMethods();
        for (Method m : methods) {
            System.out.println(m);
        }

        System.out.println("获取共有方法");
        Method eat = clazz.getMethod("eat", String.class);
        Object o = (clazz.getConstructor()).newInstance();
        eat.invoke(o, "饭");

        System.out.println("获取私有方法");
        Method peach = clazz.getDeclaredMethod("peach");
        peach.setAccessible(true);
        peach.invoke(o);
    }

}
class Food {
    public Food() {}

    public void eat(String food) {
        System.out.println("吃" + food);
    }
    protected void water() {
        System.out.println("喝水");
    }
    void apple() {
        System.out.println("吃苹果");
    }
    private void peach() {
        System.out.println("吃桃子");
    }
}
获取所有'共有'方法
public void reflect.Food.eat(java.lang.String)
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
获取所有方法(除Object方法外的所有方法)
private void reflect.Food.peach()
public void reflect.Food.eat(java.lang.String)
protected void reflect.Food.water()
void reflect.Food.apple()
获取共有方法
吃饭
获取私有方法
吃桃子

e. 动态代理

  • 在程序运行期间动态创建代理类及其实例来完成具体的功能叫做动态代理。
  • JDK动态代理的相关类和接口
    1、java.lang.reflect.Proxy用于动态生成代理类。通过调用以下方法创建新的实例。
    newProxyInstance(ClassLoader loader, Class<?> caller, Constructor<?> cons, InvocationHandler h)
    loader:被监控对象的ClassLoader
    caller:被监控对象的实现接口。
    h:调用处理器
    2、 java.lang.reflect.InvocationHandler:该接口包含一个invoke方法,通过该方法实现对委托类的代理的访问,并且添加新的业务逻辑。
public interface Subject {
    void eat(String food);
    void looks();
}
public class Panda implements Subject {
    @Override
    public void eat(String food) {
        System.out.printf("I like eating %s.\n", food);
    }

    @Override
    public void looks() {
        System.out.println("I am so cute.");
    }
}
public class DynamicProxy implements InvocationHandler {

    private Object subject;

    public DynamicProxy(Object subject) {
        this.subject = subject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //在代理对象前我们可以执行自己的一些操作
        System.out.println("before method...");
        System.out.println(method);

        // 调用代理对象的方法
        method.invoke(subject, args);

        System.out.println("after method...");
        return null;
    }

    public static void main(String[] args) {
        Subject panda = new Panda();
        InvocationHandler handler = new DynamicProxy(panda);
        Subject subject = (Subject) Proxy.newProxyInstance(panda.getClass().getClassLoader(),
                panda.getClass().getInterfaces(), handler);
        subject.eat("bamboo");
        subject.looks();

        System.out.println(subject instanceof Panda); // false
        System.out.println(subject instanceof Subject); // true
    }
before method...
public abstract void proxy.Subject.eat(java.lang.String)
I like eating bamboo.
after method...
before method...
public abstract void proxy.Subject.looks()
I am so cute.
after method...
false
true

参考文献
Java基础之—反射(非常重要)
你真的完全了解Java动态代理吗?看这篇就够了
java的动态代理机制详解

相关文章

  • Java基础:类型信息

    1. Class对象 每个类都有一个class对象,每当编写且编译了一个新类,就会产生一个Class对象(更恰当的...

  • Java 高级基础——反射

    Java 高级基础——反射 反射的意义:Java 强类型语言,但是我们在运行时有了解、修改信息的需求,包括类信息、...

  • Java知识之数据类型

    Java数据类型图表## Java数据类型分为:### 基础数据类型 引用数据类型 null类型 基础数据类型分別...

  • java基础(一),类型信息(反射)

    1、RTTI(Run-Time Type Information) 面向对象编程的基本目的是:让代码只操纵对基类的...

  • Android 面试/进阶知识点梳理

    Java基础 泛型 注解 多线程 JMM 类型信息 ClassLoader 虚拟机实现原理 垃圾回收算法 JDK ...

  • Java基础类型

    Java基础类型 Java除了8个基础类型和枚举类型外,其他的都是引用类型 整型(默认值0) 浮点型(默认值0.0...

  • java编程分类

    一、java简介java开发环境配置java基础语法java对象与类java基本数据类型java变量类型java修...

  • java类型信息

    运行时类型信息使得你能够在程序运行时发现和使用类型信息;java在运行中识别类型信息主要有两类,一是从传统的RTT...

  • Java 类型信息

    RTTI(Run-time Type Identification) Class对象,JVM,ClassLoade...

  • 大数据开发:Java数据类型入门

    在Java基础入门学习阶段,Java基础数据类型无疑是基础当中的重点,掌握基础数据类型,对于后续去理解和掌握更深入...

网友评论

      本文标题:Java基础:类型信息

      本文链接:https://www.haomeiwen.com/subject/kipzictx.html