一、内置注解
@Override:重写
@Deprecated:表示注解的方法或类不推荐使用
@SuppressWarnings:正压警告
二、使用元注解自定义注解
// 表示我们的注解可以用在哪些地方
@Target({ElementType.METHOD, ElementType.TYPE})
// 表示我们的注解在什么时候还有效
@Retention(RetentionPolicy.RUNTIME)
// 表示是否将我们的注解生成在JavaDoc中
@Documented
// 表示子类可以继承父类的注解
@Inherited
public @interface myAnnotation {
// 不加默认值的话,使用注解时必须传参!
int id();
// 如果只有一个参数,一般推荐使用value做参数名,且使用的时候直接传值就行,不用 value="..."
// 如果是其他名称就必须使用 属性名="属性值" 传值
String value() default "";
String[] typeof() default {"类型一","类型二"};
}
三、反射
3.1 获取Class对象的方法
package demo;
public class Test2 extends Object {
public static void main(String[] args) throws ClassNotFoundException {
/**
* 直接获得Class对象
*/
// 方式一:若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高
Class c1 = User.class;
// 方式二:若已知某个类的实例,调用该实例的getClass()方法获取Class对象,
User user = new User();
Class c2 = user.getClass();
// 方式三:通过Class类的静态方法forName()获取
Class c3 = Class.forName("demo.User");
// 方式四:通过ClassLoader类加载器获得Class对象
ClassLoader loader = ClassLoader.getSystemClassLoader();// 获得类加载器对象
Class c4 = loader.loadClass("demo.User");
System.out.println(c1.hashCode() + "," + c2.hashCode() + "," + c3.hashCode() + "," + c4.hashCode()); // 356573597,356573597,356573597,356573597
/**
* 间接获得类对象
*/
// 获得父类Class对象
Class c5 = c1.getSuperclass();
System.out.println(c5); // class demo.Person
/**
* 特殊情况获得类对象
*/
// 基本内置数据类型的包装类都有一个Type属性,可以直接用类名.Type
Class<Integer> type = Integer.TYPE;
System.out.println(type); // int
}
}
class Person {
public String type;
}
class User extends Person{
private String name;
private int age;
private String habit;
// 此处省略构造器、get、set、toString方法
}
3.2 获取Class对象的属性和方法
public class Test3 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
// 获得User的Class对象
Class<?> c1 = Class.forName("demo.User");
/**
* 【获得类的名字】
* getName()是获得 包名+类名
* getSimpleName()只会获得类名
*/
System.out.println(c1.getName());// demo.User
System.out.println(c1.getSimpleName());// User
System.out.println("========================================");
/**
* 【获得类的属性】
* getField() 指定属性名(只能获得public的属性,而且还能得到父类的属性)
* getDeclaredField() 能获得自己所有的属性
* getFields() 获得属性值的数组,但是使用范围同getFile一样,只能获得public属性,而且也能得到父类的public属性
* getDeclaredFields() 获得自己所有的属性值(包含private修饰的属性),返回一个数组
*/
System.out.println(c1.getField("name"));// 会报错,因为只能获得public修饰的属性
System.out.println(c1.getDeclaredField("name"));// private java.lang.String demo.User.name
Field[] f1 = c1.getFields();
Field[] f2 = c1.getDeclaredFields();
System.out.println("========================================");
/**
* 【获得类的方法】
* getMethods() 获得本类及其父类所有的仅限public修饰的方法
* getDeclaredMethods() 获得类自己所有的方法,甚至包括private,不能得到父类的方法
*/
Method[] m1 = c1.getMethods();
Method[] m2 = c1.getDeclaredMethods();
/**
* 【还有构造器之类的方法此处不做展示】
*/
}
}
3.3 使用反射示例
方法(Method)、属性(Field)、构造器(Constructor)对象都有
setAccessible()
方法,其作用是设置安全检查开关,默认为false,当参数值为true时,有两个好处:①提高访问权限,使得原来无法访问的私有成员也可以访问;②提高反射的效率;
获得User实例化对象
Class c1 = Class.forName("demo.User");
// 调用无参构造器得到User对象
User u1 = (User) c1.newInstance();
// 调用有参构造器得到User对象
Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, String.class);
User u2 = (User) constructor.newInstance("Carle", 20, "code");
获得User对象的内部方法
Class c1 = Class.forName("demo.User");
User u = (User) c1.newInstance();
// 通过反射获取方法
Method method = c1.getDeclaredMethod("setName", String.class);
// 激活方法,传入User对象和方法对应的参数
method.invoke(u, "Carle");
System.out.println(u.getName()); // Carle
获得User对象的内部属性
Class c1 = Class.forName("demo.User");
User u = (User) c1.newInstance();
// 通过反射获取属性
Field field = c1.getDeclaredField("name");
// 开启暴力反射,设置可访问性,否则无法操作private修饰的属性
field.setAccessible(true);
// 设置属性值
field.set(u, "Carle");
System.out.println(u.getName()); // Carle
通过反射操作注解
public class Test04 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c = Class.forName("demo.User");
// 通过反射获得类的注解and参数值
TableAnno anno = (TableAnno) c.getAnnotation(TableAnno.class);
System.out.println(anno); // @demo.TableAnno(value=db_Table)
System.out.println(anno.value()); // db_Table
// 通过反射获得类属性的注解and参数值
Field f = c.getDeclaredField("id");
FieldAnno anno2 = f.getAnnotation(FieldAnno.class);
System.out.println(anno2); // @demo.FieldAnno(columnName=db_id, type=int, len=16)
System.out.println(anno2.columnName()
+ "," + anno2.type()
+ "," + anno2.len()); // db_id,int,16
}
}
/**
* 自定义User类,使用自定义的一些注解
*/
@TableAnno("db_Table")
class User {
@FieldAnno(columnName = "db_id",type = "int",len = 16)
private int id;
@FieldAnno(columnName = "db_name",type = "String",len = 10)
private String name;
}
/**
* 自定义作用在类上的注解TableAnno
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableAnno {
String value();
}
/**
* 自定义作用在属性上的注解FieldAnno
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldAnno {
String columnName();
String type();
int len();
}