内置注解
-
@Override:定义在java.lang.Override中, 此注解只适用于修辞方法,表示一个方法打算重写超类中的另一个方法声明
-
@Deprecated:定义在java.lang.Deprecated中,此注解可以用于修辞方法、属性、类,表示不鼓励程序员使用这样的元素,通常是因为他很危险或者存在更好的选择。
-
@SuppressWarnings:定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息,
- 与前两个不同,需要添加一个参数才能够正确使用,这些参数都是已经定义好了的,我们选择性的使用就好了
- @SupressWarnings(“all”)
- @SupressWarnings(“unchecked”)
- @SupressWarnings(value = { “unchecked”, " deprecation"})
元注解
-
元注解的作用解释注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型做说明
-
4个元注解分别为:
@Target:用于描述注解的使用范围
@Retention:用于表示需要在什么级别保存注解信息,用于描述注解的声明周期,(SOURCE<CLASS<RUNTIME)
@Document:说明该注解将被包含在javadoc中
@Inherited:说明子类可以继承父类中的该注解
package com.hua;
import java.lang.annotation.*;
@Myannotation
public class Meta_annotation_test01 {
@Myannotation
public void test1(){
}
}
//定义一个注解
//注解的作用目标,参数是一个类型的数组
@Target(value = {ElementType.METHOD,ElementType.TYPE})
//子类可以继承父类的注解
@Inherited
//保存注解信息的级别,源代码,字节码,运行时
@Retention(value = RetentionPolicy.RUNTIME)
//注解被包含在javadoc中
@Documented
@interface Myannotation{
}
自定义注解
- 使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
- 分析
- @interface用来声明一个注解,格式: public @interface 注解名 {定义内容}
- 其中的每一个方法实际上是声明了一个配置参数
- 方法的名称就是参数的名称
- 返回值类型就是参数的类型(返回值只能是基本类:Class(不是class), String, enum)
- 可以通过default来声明参数的默认值
- 如果只有一个参数成员,一般参数名为value
- 注解元素必须要有值,我们定义注解元素时,经常使用空字符串,0作为默认值。
一般先定target和retention,
package com.hua;
import javax.xml.bind.Element;
import java.lang.annotation.*;
public class Self_Define_Annotation {
@MyAnnotation2(age = 20,id = 1)
public void test(){
}
@MyAnnotation3("")
public void test2(){
}
}
@Inherited
@Documented
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD,ElementType.TYPE})
@interface MyAnnotation2{
//注解的参数:参数类型 参数名();
String name() default "";
int age() default 18;
int id() default -1;//-1代表不存在;
String[] schools() default {"hdu","tinghua"};
}
//只有一个参数,用value命名,可以默认为""
@Target(value = {ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3{
String value();
}
反射机制
静态语言 VS 动态语言
- 动态语言
- 是一类在运行时,可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构。
- 主要动态语言:Object-C, C#, JavaScript, PHP, Python等
- 静态语言
- 与动态语言对应,运行时结构不可变的语言就是静态语言,如C,C++, Java;
- Java不是动态语言,但Java可以称为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制获得类似动态语言的特性。Java的动态性让Java编程的时候更加灵活。 Java获取了一定的动态性,作为代价就失去了一部分的安全性。
Java Reflection
-
Reflection 是Java被视为动态语言的关键,反射机制允许程序在执行期间借助Reflection API取得任何类的内部信息,并且能直接操作任意对象的内部属性及方法。
Class c = Class.forName("java.lang.String");
-
记载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构。所以,我们形象的称之为:反射。
//通过类反射取得类的class对象,一个类在内存中只有一个class对象
//一个类被加载后,整个类的结构会被封装在class对象中
-
java反射机制提供的功能
-
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时获取泛型信息
- 在运行时调用任意一个对象的成员变量和方法
- 生成动态代理
- …
- 反射优缺点
- 优点:可以实现动态创建对象和编译,体现出很大的灵活性
- 缺点:对性能有影响。使用反射基本上是一种解释性操作,我们可以告诉JVM,我们希望做什么并且它会满足我么的呢需求,这类操作总是慢于直接执行相同的操作。
-
-
反射获取类的方法
package com.hua.reflection; public class Creating_Method { public static void main(String[] args) throws ClassNotFoundException { Student person=new Student(); //方法1:通过对象获得 Class c1=person.getClass(); System.out.println(c1.hashCode()); //方法2:forname获得 Class c2=Class.forName("com.hua.reflection.Student"); System.out.println(c2.hashCode()); //方法3:通过类名.class获得 Class c3=Student.class; System.out.println(c3.hashCode()); //获得父类类型 Class c1father=c1.getSuperclass(); System.out.println(c1father); } } class Person{ String name; public Person(String name) { this.name = name; } public Person(){ } @Override public String toString() { return "Person{" + "name='" + name + '\'' + '}'; } } class Student extends Person{ public Student(){ this.name="老师"; } } class Teacher extends Person{ public Teacher(){ this.name="学生"; } }
-
哪些类有class对象
package com.hua.reflection; import javax.xml.bind.Element; public class Class_Of_Type { 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= Element.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); } }
类的加载
当程序主动使用某个类的时候,如果该类还没有被加载到内存中,则系统会通过如下三个步骤对该类进行初始化。
- 加载:将class字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象
- 链接:将Java类的二进制代码合并到JVM的运行状态之中的过程。
- 验证:确保加载的类信息符合JVM规范,没有安全方面的问题
- 准备:类变量(static)分配内存并设置类变量默认值的阶段,这些内存都将在方法区中进行分配。
- 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。
- 初始化:
- 执行类构造器()方法的过程。类构造器()方法将类中所有静态代码块和静态变量的赋值动作中的语句合并产生的。(类构造器是构造信息的,不是构造该类对象的构造器)。
- 当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发父类的初始化。
- 虚拟机会保证一个类的()方法在多线程环境中被正确的加锁和同步
什么时候会加载类呢?
package com.hua.reflection;
public class Class_Loader {
public static void main(String[] args) {
A a=new A();
System.out.println(a.m);
}
}
class A{
//静态代码块
static{
System.out.println("静态代码块初始化");
}
//静态变量
static int m=100;
public A(){
System.out.println("无参构造初始化");
}
}
获取类的结构
package com.hua.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Get_Class_Construction {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class c1=Class.forName("com.hua.reflection.User");
//获取包名+类名
System.out.println(c1.getName());
//获取包名
System.out.println(c1.getSimpleName());
//获取类的属性
Field[] fields=c1.getFields();//只有public属性
fields=c1.getDeclaredFields();//获取全部属性
for (Field field : fields) {
System.out.println(field);
}
//获取指定属性
Field id=c1.getDeclaredField("id");
System.out.println(id);
//获取类的方法
Method[] methods=c1.getDeclaredMethods();//获得本类的所有方法
for (Method method : methods) {
System.out.println(method);
}
//获得指定方法
Method method=c1.getDeclaredMethod("setAge", int.class);
System.out.println(method);
//获得指定构造器
Constructor[] constructors=c1.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
Constructor constructor=c1.getDeclaredConstructor(String.class,int.class,int.class);
System.out.println(constructor);
}
}
动态创建类的对象
用class对象创建对象
package com.hua.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Reflect_Create_Obj {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Class c1=Class.forName("com.hua.reflection.User");
//newInstance返回的是一个Object对象,调用的是无参构造器
User user=(User)c1.newInstance();
System.out.println(user);
//先获取有参构造器,再用有参构造器newinstance一个对象
Constructor constructor=c1.getDeclaredConstructor(String.class,int.class,int.class);
User user2=(User)constructor.newInstance("hua",001,19);
System.out.println(user2);
//通过反射调用方法,先创建一个无参对象,再invoke调用指定的方法
User user3=(User)c1.newInstance();
Method setName=c1.getDeclaredMethod("setName", String.class);
setName.invoke(user3,"hua");
System.out.println(user3);
//通过反射操作属性
User user4=(User)c1.newInstance();
Field name=c1.getDeclaredField("name");
//属性值是private,不能直接访问,要关闭权限检测
name.setAccessible(true);
name.set(user4,"hua2");
System.out.println(user4.getName());
}
}
通过反射得到注解的信息
package com.hua.reflection;
import java.lang.annotation.*;
import java.lang.reflect.Field;
public class Reflection_Get_Annotation {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c1=Class.forName("com.hua.reflection.Student2");
//通过反射获取注解
Annotation[] annotations=c1.getDeclaredAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
// 通过反射获取注解的值
//得到类的注解
Table table=(Table) c1.getDeclaredAnnotation(Table.class);
//再得到注解的值
String value=table.value();
System.out.println(value);
//获得类指定的注解
//先得到指定的属性
Field f=c1.getDeclaredField("id");
//再通过属性得到属性的注解
field annotation=f.getAnnotation(field.class);
System.out.println(annotation.comlumn_name());
System.out.println(annotation.type());
System.out.println(annotation.length());
}
}
@Table("tab_Stu")
class Student2{
@field(comlumn_name = "stu_id",type = "int",length = 10)
private int id;
@field(comlumn_name = "stu_age",type = "int",length = 10)
private int age;
@field(comlumn_name = "stu_name",type = "string",length = 10)
private String name;
public Student2(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Target(ElementType.TYPE)
@Retention(value = RetentionPolicy.RUNTIME)
@interface Table{
String value();
}
@Target(ElementType.FIELD)
@Retention(value = RetentionPolicy.RUNTIME)
@interface field{
String comlumn_name();
int length();
String type();
}