Java知识点06——注解(Annotation)、类加载机制、反射
声明:
- 该资料来自自己整理。
- 参考书籍
疯狂 Java讲义(第五版) 李刚?著
一、注解
1.1 标记注解(Annotation)
@Override
限定重写父类方法:@Override
class Fruit{
public void info(){
System.out.println("Fruit的info方法...");
}
}
public class AnnotationTest extends Fruit{
@Override
public void info() {
System.out.println("AnnotationTest重写Fruit的info方法...");
}
}
注意:@Override只能修饰方法,不能修饰其它程序元素
@Deprecated
@Deprecated 用于标识某个程序元素(类,方法等)已过时,当其它程序使用已过时的类、方法时,编译期将会给出警告。
@Deprecated注解增加了如下两个属性:(JDK9 新增的)
forRemoval :该boolean类型的属性指定该API在将来是否会被删除。since :该String类型的属性指定该API从哪个版本被标记为过时。
class Fruit{
@Deprecated
public void info2(){
System.out.println("即将过时的方法...");
}
}
public class AnnotationTest extends Fruit{
public static void main(String[] args) {
new Fruit().info2();
}
}
@SuppressWarnings
抑制编译器警告:@SuppressWarning
@SuppressWarning指示被该注解修饰的程序元素(以及该程序元素中的所有子元素),取消显式指定的编译器警告。@SuppressWarning会一直作用于该程序元素的所有子元素。只能保存在源码级别上。
@SuppressWarnings(value = "unchecked")
public class SuppressWarningTest {
public static void main(String[] args) {
List<String> myList = new ArrayList<>();
}
}
使用@SuppressWarning注解来关闭编译器警告时,一定要在括号里使用 name=value 的形式为该注解的成员变量设置值。
@SafeVarargs
”堆污染“警告与@SafeVarargs。
当把一个不带泛型的独享赋给一个带反省的变量时,往往会发生”堆污染“。例如:
List<String> listStrArray = new List<String>();
List[] listArray = listStrArray;
抑制该堆污染警告有如下三种方式:
- 使用
@SafeVarargs 修饰修饰引发该警告的方法或构造器。JDK 9允许使用该注释修饰私有实例方法。 - 使用
@SuppressWarnings("unchecked") 修饰。 - 编译时使用
-Xlint:varargs 选项。
@FunctionalInterface
@FunctionalInterface就是用来指定某个接口必须是函数式接口。
@java.lang.FunctionalInterface
public interface FunctionalInterface {
void test();
}
@FunctionalInterface只能修饰接口,不能修饰其他程序元素。
1.2 元注解(meta-annotation)
@Retention【重点】
@Retention:表示需要在什么级别保存该注释信息,用于描述注解的声明周期。
(SOURCE < CLASS < RUNTIME )
@Target 【重点】
@Target :用于描述注解的使用范围(即:被描述的注解可用在什么地方)
@Document
@Document :说明该注释将被包含在javadoc中。
@Inherited
@Inherited :说明子类可以继承父类中的该注释。
1.3 自定义注解
@interface 关键字
public @interface Test(){
}
@Test
public class MyClass{
@Test
public void info(){···}
}
1.4 AnnotatedElement 接口
实现类:
1.4.1 提取注解信息
java.lang.reflect 包所提供的反射 API 增加了读取运行时注解的能力。
只有当定义注解时使用了@Rentention(RetentionPolicy.RUNTIME) 修饰,该注解才会在运行时可见,JVM才会在装载 *.class 文件时读取保存在 class 文件中的注解信息。
二、类加载机制
2.1 JVM 和 类
例如【注意细节】:
public class A {
public static int a = 6;
}
public class ATest {
public static void main(String[] args) {
A a = new A();
a.a ++;
System.out.println(a.a);
}
}
public class ATest2 {
public static void main(String[] args) {
A b = new A();
System.out.println(b.a);
}
}
2.2 类的加载(类初始化)步骤
2.2.1 类的加载(步骤一)
一个类在内存中只有一个Class对象;一个类被加载后,类的整个结构都会被封装在Class对象中。
2.2.2 类的连接(步骤二)
2.2.3 类的初始化(步骤三)
当程序主动使用任何一个类时,系统会保证该类以及所有父类(包括直接父类和间接父类)都会先被初始化。
2.3 类初始化的时机
注意:一
class MyTest{
static{
System.out.println("静态初始化块...");
}
static final String compileConstant = "go go go";
}
public class CompileConstantTest {
public static void main(String[] args) {
System.out.println(MyTest.compileConstant);
}
}
注意:二
2.4 类加载器
【案例】
public class ClassLoaderTest {
public static void main(String[] args) throws ClassNotFoundException {
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println("系统类的加载器:"+systemClassLoader);
ClassLoader parent = systemClassLoader.getParent();
System.out.println("扩展类加载器:"+parent);
ClassLoader parentRoot = parent.getParent();
System.out.println("根加载器(C/C++):"+parentRoot);
ClassLoader classLoader = Class.forName("JVMAndClass.ClassLoaderTest").getClassLoader();
System.out.println("当前类的加载器:"+classLoader);
classLoader = Class.forName("java.lang.Object").getClassLoader();
System.out.println("JDK内置的加载器是谁加载的:"+classLoader);
System.out.println(System.getProperty("java.class.path"));
}
}
三、反射
3.1 简介
获取对象的方式:
3.2 优缺点
优点: 可以实现动态创建对象和编译,体现出很强的灵活性。
缺点: 对性能有影响。
3.3 主要API
java.lang.Class :代表一个类java.lang.reflect.Method :代表类的方法java.lang.reflect.Field :代表类的成员变量java.lang.reflect.Constructor :代表类的构造器
3.4 获取Class类的实例
【案例】
public class Reflaction01 {
public static void main(String[] args) throws ClassNotFoundException {
Student student = new Student();
System.out.println("这个人是:"+student.name);
Class c1 = student.getClass();
System.out.println(c1.hashCode());
Class c2 = Class.forName("reflaction.Student");
System.out.println(c2.hashCode());
Class c3 = Student.class;
System.out.println(c3.hashCode());
Class c4 = Integer.TYPE;
System.out.println(c4);
Class superclass = c1.getSuperclass();
System.out.println(superclass);
}
}
class Person{
public 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 = "老师"; }
}
3.5 所有类型的Class
public class AllClass {
public static void main(String[] args) {
Class c1 = Object.class;
Class c2 = Comparable.class;
Class c3 = String[].class;
Class c4 = int[][].class;
Class c5 = Override.class;
Class c6 = ElementType.class;
Class c7 = Integer.class;
Class c8 = void.class;
Class c9 = 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);
int[] a = new int[10];
int[] b = new int[100];
System.out.println(a.getClass().hashCode());
System.out.println(b.getClass().hashCode());
}
}
3.6 通过反射查看类信息
4.5.1、获得Class对象
4.5.2、从Class中获取信息
返回Class对应类的构造器 返回Class对应类所包含的方法 返回Class对应类所包含的成员变量 返回Class对应类所包含的Annotation 返回Class对应类所包含的内部类、外部类、实现的接口、所继承的父类 返回Class对应类的修饰符、所在包、类名等基本信息
4.5.3、JDK 8新增的方法参数反射
class Test{
public void replace(String str, List<String> list){}
}
public class MethodParameterTest {
public static void main(String[] args) throws NoSuchMethodException {
Class<Test> testClass = Test.class;
Method replace = testClass.getMethod("replace", String.class, List.class);
System.out.println("replace方法参数个数:"+replace.getParameterCount());
Parameter[] parameters = replace.getParameters();
int index = 1;
for (Parameter p : parameters){
if (p.isNamePresent()){
System.out.println("----第"+ index++ +"个参数信息----");
System.out.println("参数名:"+p.getName());
System.out.println("参数类型:"+p.getType());
System.out.println("泛型类型:"+p.getParameterizedType());
}
}
}
}
4.5.4、练习
@Repeatable(Annos.class)
@interface Anno{}
@Retention(value = RetentionPolicy.RUNTIME)
@interface Annos{
Anno[] value();
}
@SuppressWarnings(value = "unchecked")
@Deprecated
@Anno
@Anno
public class ClassTest {
private ClassTest(){}
public ClassTest(String name){
System.out.println("执行有参数的构造器");
}
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 NoSuchMethodException, ClassNotFoundException {
Class<ClassTest> classTestClass = ClassTest.class;
System.out.println("ClassTest的带一个参数的构造器如下");
System.out.println("一个参数构造器-->"+classTestClass.getConstructor(String.class));
Constructor<?>[] constructors = classTestClass.getConstructors();
System.out.println("ClassTest的public构造器如下");
for (Constructor constructor : constructors){
System.out.println("constructor-->"+constructor);
}
Constructor<?>[] declaredConstructors = classTestClass.getDeclaredConstructors();
System.out.println("ClassTest的全部构造器如下");
for (Constructor declaredConstructor : declaredConstructors){
System.out.println("declaredConstructor-->"+declaredConstructor);
}
System.out.println("ClassTest的带一个参数的方法如下");
System.out.println("一个参数方法-->"+classTestClass.getMethod("info", String.class));
Method[] methods = classTestClass.getMethods();
System.out.println("ClassTest的public方法如下");
for (Method method : methods){
System.out.println("method-->"+method);
}
Method[] declaredMethods = classTestClass.getDeclaredMethods();
System.out.println("ClassTest的public方法如下");
for (Method declaredMethod : declaredMethods){
System.out.println("declaredMethod-->"+declaredMethod);
}
System.out.println("该Class对象对应类的全部注解如下");
Annotation[] annotations = classTestClass.getAnnotations();
for (Annotation annotation : annotations){
System.out.println("annotation-->"+annotation);
}
System.out.println("该Class元素上的@SuppressWarnings注解为-->"+classTestClass.getAnnotationsByType(SuppressWarnings.class));
Class<?>[] declaredClasses = classTestClass.getDeclaredClasses();
System.out.println("ClassTest的全部内部类如下:");
for (Class declaredClass : declaredClasses){
System.out.println("declaredClass-->"+declaredClass);
}
Class<?> innerClass = Class.forName("reflaction.ClassTest$Inner");
System.out.println("innerClass-->"+innerClass);
System.out.println("Inner内部类所在的外部类-->"+innerClass.getDeclaringClass());
System.out.println("ClassTest的包为-->"+classTestClass.getPackage());
System.out.println("ClassTest的父类为-->"+classTestClass.getSuperclass());
}
}
3.7 动态创建对象执行方法
setAccessible()方法 :
public class CreateInstanceUseMethod {
public static void main(String[] args) throws Exception {
Class<?> c1 = Class.forName("reflaction.Person");
Person p = (Person) c1.newInstance();
System.out.println(p);
Constructor<?> constructor = c1.getDeclaredConstructor(String.class);
Person p2 = (Person) constructor.newInstance("孙悟空");
System.out.println(p2);
Person p3 = (Person) c1.newInstance();
Method setName = c1.getDeclaredMethod("setName", String.class);
setName.invoke(p3,"唐僧");
System.out.println(p3.getName());
System.out.println("----------通过反射操作属性----------");
Person p4 = (Person) c1.newInstance();
Field id = c1.getDeclaredField("id");
id.setAccessible(true);
id.set(p4,999);
System.out.println(p4.getId());
}
}
3.8 性能比较
public class PerformanceTest {
static void test1(){
Person p = new Person();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
p.getId();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方式执行10亿次:"+(endTime-startTime)+"ms");
}
static void test2() throws Exception {
Person p = new Person();
Class<? extends Person> c1 = p.getClass();
Method getName = c1.getDeclaredMethod("getName", null);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(p,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射方式执行10亿次:"+(endTime-startTime)+"ms");
}
static void test3() throws Exception {
Person p = new Person();
Class<? extends Person> c1 = p.getClass();
Method getName = c1.getDeclaredMethod("getName", null);
getName.setAccessible(true);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(p,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射关闭检测方式执行10亿次:"+(endTime-startTime)+"ms");
}
public static void main(String[] args) throws Exception {
test1();
test2();
test3();
}
}
|