类型信息:反射-Class

2024-09-08 12:32
文章标签 反射 class 类型信息

本文主要是介绍类型信息:反射-Class,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在说反射前提一个概念:RTTI(在运行时,识别一个对象的类型)

public class Shapes {public static void main(String[] args) {List<Shape> shapes = Arrays.asList(new Circle(), new Square(), new Triangle());for (Shape shape : shapes) {shape.draw();}}
}
abstract class Shape{void draw() {System.out.println(this + ".draw()");}abstract public String toString();
}
class Circle extends Shape{@Overridepublic String toString() {return "circle";}
}
class Square extends Shape{@Overridepublic String toString() {return "square";}
}
class Triangle extends Shape {@Overridepublic String toString() {return "triangle";}
}
在这个例子中,RTTI类型转换并不彻底:Object被转型为Shape,而不是转型为其子类。这是因为目前我们只知道这个list<shape>保存的都是Shape。在编译时,将交由容器和java泛型系统来强制确保这一点;而在运行时,有类型转换来确保这一点。接下来就是多态机制了。

但是,假如碰到这么一个特殊的问题——我们想要找到其中一种形状图案将它全部变为某种颜色,该怎么办呢?我们通过以上代码并没有办法去获得具体的类型。这就需要RTTI了。

要理解RTTI在java中的工作原理,首先必须知道类型信息在运行时是如何表示的——Class对象。Class对象包含了与类有关信息。java是面向对象的语言,我们可以通过创建类来抽象某一对象,也可以通过Class来抽象这些类。每个类都有一个Class对象。就是每当你执行javac编译的时候,你创建的类就会产生一个Class对象(.class文件)。所有的类都是在对其第一次使用时,动态加载到JVM中的。当程序创建第一个对类的静态成员的引用时,就会加载这个类。这个也证明了构造器也是类的静态方法,虽然在构造器之前并没有使用static关键字,但是new操作符创建类的新对象也会被当作类的静态成员的引用。由此得出,java程序在它开始运行之前并非被完全加载。其各部分是在必需时才加载的。

一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有对象。所以在你更改了这个类的代码时,必须重新编译,否则程序还是执行你上一次编译后的Class对象.

public class SweetShop {public static void main(String[] args) {System.out.println("inside main");new Candy();System.out.println("after creating Candy");try {Class.forName("com.test.Gum");} catch (ClassNotFoundException e) {System.out.println("Couldn't create Gum");e.printStackTrace();}System.out.println("after creating Gum");new Cookie();System.out.println("after creating Cookie");}
}
class Candy {static {System.out.println("loading Candy");}
}
class Cookie {static {System.out.println("loading Cookie");}
}
public class Gum {static {System.out.println("loading Gum");}
}
Note:Class.forName("必须是 classpath中(包名.类名)")。也就是说在使用Class.forName()的时候必须使用类的全名,这个全名包括类所在的包名。否则会抛出ClassNotFoundException。
public class FancyToy extends Toy implements HasBatt, Waterproof,Shoots {FancyToy() {super(1);}
}
class Toy {Toy() {}Toy(int i) {}
}
interface HasBatt{}
interface Waterproof{}
interface Shoots{}public class ToyTest {static void printInfo(Class cc) {System.out.println("Class name: "+cc.getName()+"is interface?["+ cc.isInterface() +"]");System.out.println("Simple name: "+cc.getSimpleName());System.out.println("Canonical name: "+cc.getCanonicalName());}public static void main(String[] args) {Class c = null;try {c = Class.forName("test0830.FancyToy");} catch (ClassNotFoundException e) {System.out.println("can't find FancyToy");}printInfo(c);System.out.println("----------------");for (Class face : c.getInterfaces()) {printInfo(face);}System.out.println("--------------");Class up = c.getSuperclass();Object obj = null;try {obj = up.newInstance();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}printInfo(obj.getClass());}
}
运行后的结果:
Class name: test0830.FancyToyis interface?[false]
Simple name: FancyToy
Canonical name: test0830.FancyToy
----------------
Class name: test0830.HasBattis interface?[true]
Simple name: HasBatt
Canonical name: test0830.HasBatt
Class name: test0830.Waterproofis interface?[true]
Simple name: Waterproof
Canonical name: test0830.Waterproof
Class name: test0830.Shootsis interface?[true]
Simple name: Shoots
Canonical name: test0830.Shoots
--------------
Class name: test0830.Toyis interface?[false]
Simple name: Toy
Canonical name: test0830.Toy

三种获取Class对象的方法:

public class ClassTest {public static void main(String[] args) throws ClassNotFoundException {String str = new String("abc");System.out.println(Class.forName("java.lang.String"));System.out.println(str.getClass());System.out.println(java.lang.String.class);}
}

从Class对象中获取类名:getName:类的全名(包括包名),getSimpleName:类的名称(不包括包名)

public class ClassTest {public static void main(String[] args) throws ClassNotFoundException {String str = new String("abc");Class aClass = Class.forName("java.lang.String");System.out.println("--------获取类名--------");String className = aClass.getName();System.out.println("aClass.getName():" + className);String classSimpleName = aClass.getSimpleName();System.out.println("aClass.getSimpleName():" + classSimpleName);}
}
运行结果:
--------获取类名--------
aClass.getName():java.lang.String
aClass.getSimpleName():String
获取修饰符:
import java.lang.reflect.Modifier;public class ClassTest {public static void main(String[] args) throws ClassNotFoundException {String str = new String("abc");Class aClass = Class.forName("java.lang.String");System.out.println("--------获取类名--------");String className = aClass.getName();System.out.println("aClass.getName():" + className);String classSimpleName = aClass.getSimpleName();System.out.println("aClass.getSimpleName():" + classSimpleName);System.out.println("--------获取修饰符-------");int modifiers = aClass.getModifiers();//是否是抽象类型System.out.println("Modifier.isAbstract(modifiers): " + Modifier.isAbstract(modifiers));//是否是finalSystem.out.println("Modifier.isFinal(modifiers): " + Modifier.isFinal(modifiers));//是否是接口System.out.println("Modifier.isInterface(modifiers): " + Modifier.isInterface(modifiers));//是否是nativeSystem.out.println("Modifier.isNative(modifiers): " + Modifier.isNative(modifiers));//是否是私有类型System.out.println("Modifier.isPrivate(modifiers): " + Modifier.isPrivate(modifiers));//是否是保护类型System.out.println("Modifier.isProtected(modifiers): " + Modifier.isProtected(modifiers));//是否是公有类型System.out.println("Modifier.isPublic(modifiers): " + Modifier.isPublic(modifiers));//是否是静态类型System.out.println("Modifier.isStatic(modifiers): " + Modifier.isStatic(modifiers));//是否是精确浮点类型System.out.println("Modifier.isStrict(modifiers): " + Modifier.isStrict(modifiers));//是否加有同步锁System.out.println("Modifier.isSynchronized(modifiers): " + Modifier.isSynchronized(modifiers));//标记为transient的变量,在对象存储时,这些变量状态不会被持久化。当对象序列化的保存在存储器上时,不希望有些字段数据被保存,为了保证安全性,可以把这些字段声明为transientSystem.out.println("Modifier.isTransient(modifiers): " + Modifier.isTransient(modifiers));//在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。System.out.println("Modifier.isVolatile(modifiers): " + Modifier.isVolatile(modifiers));}
}

执行结果:

--------获取类名--------
aClass.getName():java.lang.String
aClass.getSimpleName():String
--------获取修饰符-------
Modifier.isAbstract(modifiers): false
Modifier.isFinal(modifiers): true
Modifier.isInterface(modifiers): false
Modifier.isNative(modifiers): false
Modifier.isPrivate(modifiers): false
Modifier.isProtected(modifiers): false
Modifier.isPublic(modifiers): true
Modifier.isStatic(modifiers): false
Modifier.isStrict(modifiers): false
Modifier.isSynchronized(modifiers): false
Modifier.isTransient(modifiers): false
Modifier.isVolatile(modifiers): false

Class的其他方法:

public class ClassTest {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {Class aClass = Class.forName("java.util.HashMap");System.out.println("--------父类-------");System.out.println("getSuperclass(): " + aClass.getSuperclass());System.out.println("--------包名-------");System.out.println("getPackage(): " + aClass.getPackage());System.out.println("------实现的接口----");System.out.println("getInterfaces()" + aClass.getInterfaces());System.out.println("-------构造器------");System.out.println("getConstructors(): " + aClass.getConstructors());System.out.println("--------方法-------");System.out.println("getMethods(): " + aClass.getMethods());System.out.println("--------变量-------");System.out.println("getFields(): " + aClass.getFields());System.out.println("--------注解-------");System.out.println("getAnnotations(): " + aClass.getAnnotations());}
}
执行结果:

--------父类-------
getSuperclass(): class java.util.AbstractMap
--------包名-------
getPackage(): package java.util, Java Platform API Specification, version 1.8
------实现的接口----
getInterfaces()[Ljava.lang.Class;@7f31245a
-------构造器------
getConstructors(): [Ljava.lang.reflect.Constructor;@6d6f6e28
--------方法-------
getMethods(): [Ljava.lang.reflect.Method;@12a3a380
--------变量-------
getFields(): [Ljava.lang.reflect.Field;@29453f44
--------注解-------
getAnnotations(): [Ljava.lang.annotation.Annotation;@6e0be858

java提供了一种叫做类字面常量的方法来生成Class对象的引用。 类名.class。这样做不仅更简单,而且更安全。因为它在编译时就会受到检查(因此不需要置于try{}catch{}语句块中)并且根除了对 .forName()方法的调用,所以更高效。

类字面常量不仅可以应用于普通类,还可以应用到接口、数组以及基本数据类型。另外对于基本数据类型的包装类,还有一个标准字段TYPE,TYPE是一个引用,指向对应的基本数据类型的Class对象。

boolean.class->Bolean.TYPE

char.class->Character.TYPE

byte.class->Byte.TYPE

short.class->Short.TYPE

int.class->Integer.TYPE

long.class->Long.TYPE

float.class->Float.TYPE

double.class->Double.TYPE

void.class->Void.TYPE

建议使用“.class”的形式,以保持与普通类的一致性。

注意:当使用“.class”来创建对Class对象的引用时,不会自动的初始化该Class对象。为了使用类而做的准备工作实际包含3个步骤:

1、加载。这是由类加载器执行的。该步骤将查找字节码(通常在classpath所指定的路径中查找,但并非是必需的),并从这些字节码中创建一个Class对象。

2、链接。在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必须的话,将解析这个类创建的对其他类的所有引用。

3、初始化。如果该类具有超类,则对其初始化,执行静态初始化器和静态初始化块。

初始化被延迟到了静态方法(构造器是隐式静态方法)或者非 常数 静态域进行首次引用才执行。

public class ClassInitialization {public static Random random = new Random(47);public static void main(String[] args) throws ClassNotFoundException {Class initable = Initable.class;System.out.println("after creating Initable ref");System.out.println(Initable.staticFinal);System.out.println(Initable.staticFinal2);System.out.println(Initable2.staticNonFinal);Class initable3 = Class.forName("test97.Initable3");System.out.println("after creating Initable3 ref");System.out.println(Initable3.staticNonsFinal);}
}
class Initable{static final int staticFinal = 47;static final int staticFinal2 = ClassInitialization.random.nextInt(1000);static {System.out.println("hello Initable");}
}class Initable2{static final int staticNonFinal = 147;static {System.out.println("hello Initable2");}
}class Initable3{static final int staticNonsFinal = 74;static {System.out.println("hello Initable3");}
}

执行结果:

after creating Initable ref
47
hello Initable
258
147
hello Initable3
after creating Initable3 ref
74

如上的执行结果可以看出,使用.class来获取Class类的引用不会引起类的初始化。但是使用Class.forName()会引起类的初始化。

Class类的方法的使用:

package test97;import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;/*** Created by Ernest on 2016/9/21.*/
@SuppressWarnings(value = "unchecked")
@Deprecated
public class ClassTest {public ClassTest() {}public ClassTest(String name) {System.out.println("执行有参数的构造器:"+name);}public void info() {System.out.println("执行无参info()方法");}public void info(String str) {System.out.println("执行有参info()方法: "+str);}//定义一个测试用的内部类class inner{}public static void main(String[] args) throws Exception {Class<ClassTest> clazz = ClassTest.class;//获取该class对象所对应类的全部构造器Constructor[] cons = clazz.getDeclaredConstructors();System.out.println("classTest的全部构造器如下:");for (Constructor con : cons) {System.out.println(con);}System.out.println("------------------");//获取该class对象所对应类的全部public构造器Constructor[] consPublic = clazz.getConstructors();System.out.println("classTest的全部public构造器如下: ");for (Constructor con : consPublic) {System.out.println(con);}System.out.println("-------------------");//获取class对象所对应类的全部public方法Method[] methods = clazz.getMethods();System.out.println("classTest的全部public方法如下: ");for (Method method : methods) {System.out.println(method);}System.out.println("--------------------");//获取class对象所对应类的指定方法Method mthd = clazz.getMethod("info", String.class);System.out.println(mthd);//获取该class对象所对应类的全部注解Annotation[] annos = clazz.getAnnotations();System.out.println("classTest的全部注解如下: ");for (Annotation anno : annos) {System.out.println(anno);}System.out.println("---------------");//获取该class对象所对应类的指定注解Annotation anno = clazz.getAnnotation(SuppressWarnings.class);System.out.println(anno);//获取该class对象所对应类的全部内部类Class<?>[] inners = clazz.getDeclaredClasses();System.out.println("classTest的全部内部类如下: ");for (Class<?> inner : inners) {System.out.println(inner);}System.out.println("----------------");//是用Class.forName方法加载ClassTest的Inner内部类Class inClass = Class.forName("test97.ClassTest$inner");System.out.println(inClass);System.out.println("inClass对应类的外部类为: "+inClass.getDeclaringClass());System.out.println("ClassTest的包: " + clazz.getPackage());System.out.println("ClassTest的父类: " + clazz.getSuperclass());}}









这篇关于类型信息:反射-Class的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1148118

相关文章

【反射知识点详解】

Java中的反射(Reflection)是一个非常强大的机制,它允许程序在运行时检查或修改类的行为。这种能力主要通过java.lang.reflect包中的类和接口来实现。 通过反射,Java程序可以动态地创建对象、调用方法、访问字段,以及获取类的各种信息(如构造器、方法、字段等)。 反射的用途 反射主要用于以下几种情况: 动态创建对象:通过类的Class对象动态地创建其实例。访问类的字段

Go 在orm中使用反射

作为静态语言,golang 稍显笨拙,还好 go 的标准包reflect(反射)包弥补了这点不足,它提供了一系列强大的 API,能够根据执行过程中对象的类型来改变程序控制流。本文将通过设计并实现一个简易的 mysql orm 来学习它,要求读者了解mysql基本知识,并且跟我一样至少已经接触 golang 两到三个月。 orm 这个概念相信同学们都非常熟悉,尤其是写过rails的同学,对acti

react笔记 8-17 属性绑定 class绑定 引入图片 循环遍历

1、绑定属性 constructor(){super()this.state={name:"张三",title:'我是一个title'}}render() {return (<div><div>aaaaaaa{this.state.name}<div title={this.state.title}>我是一个title</div></div></div>)} 绑定属性直接使用花括号{}   注

单例模式以及反射对单例模式的破坏及防御

单例模式(Singleton Pattern)是一种确保类在应用程序生命周期内只存在一个实例的设计模式。它不仅提供了全局访问点,还能节省内存、控制实例的生命周期。但常见的单例模式实现方式如饿汉式、懒汉式、双重校验锁、静态内部类等,虽然设计良好,但都容易被 Java 的反射机制所破坏。本文将介绍这些单例实现方式的优缺点、反射如何破坏它们的唯一性,以及如何防御这种破坏。 1. 单例模式的常见实现

servlet用反射代替if..else

String methodName = request.getParameter("method"); Method method = this.getClass().getDeclaredMethod(methodName,HttpServletRequest.class, HttpServletResponse.class); method.invoke(this, request, re

Redis缓存 自定义注解+aspect+反射技术实现

最近再给云随笔后台增加redis模块,突然发现spring-boot-starter-data-redis模块很不人性化,实现不了通用的方式,(当然,你也可以自己写个通用的CacheUtil来实现通用的方式),但由于本人非常的爱装逼,就在这里不讲解那种傻瓜式操作了,这里只讲干货,干到你不可置信的干货). 例如:这里我使用了它其中的RedisTemplate ,发现存到redis中后,数据

泛型参Class、Class、Class的对比区别

1.原文链接 泛型参Class、Class、Class的对比区别 https://blog.csdn.net/jitianxia68/article/details/73610606 <? extends T>和<? super T> https://www.cnblogs.com/drizzlewithwind/p/6100164.html   2.具体内容: 泛型参数Class、

c++通用模板类(template class)定义实现详细介绍

有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同,如下面语句声明了一个类:class Compare_int { public : Compare(int a,int b) { x=a; y=b; } int max( ) { return (x>y)?x:y; } int min( ) { return (x&... 有时,有两个或多个类,其功能是相同的,仅仅是数

Python方法:__init__,__new__,__class__的使用详解

转自:https://blog.csdn.net/qq_26442553/article/details/82464682 因为python中所有类默认继承object类。而object类提供了了很多原始的内建属性和方法,所以用户自定义的类在Python中也会继承这些内建属性。可以使用dir()函数可以查看,虽然python提供了很多内建属性但实际开发中常用的不多。而很多系统提供的内建属性实际

SpringBoot启动报错Failed to determine a suitable driver class

两种解决办法 1.在Application类上加 ` @EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class}) package com.example.demo3;import org.springframework.boot.SpringApplication;import org.springframewo