一, 注解(Annotation)
①Annotation是从JDK5.0开始引入的新技术
②Annotation的作用:不是程序本身,可以对程序作出解释,可以被其他程序读取
③Annotation的格式—@注释名,例如@SuppressWarnings(value=“unchecked”)
④Annotation使用的地方
可以附加在package、class、method、field等上面,相当于给他们添加了额外的辅助信息,可以通过反射机制编程实现对这些元数据的访问
①@Override—定义在java.lang.Override中,表示方法被重写
常见的toString方法等
②@Deprecated—定义在java.lang.Deprecated中,表示不鼓励程序员使用这样的元素
③@SuppressWarnings—定义在java.lang.SupressWarnings中,用来抑制编译时的警告信息
@SuppressWarnings("all")
public static void test02(){
List list = new ArrayList<>();
}
不加@SuppressWarnings,就会出现警告信息
@SuppressWarnings是有参数的注解
@Target:用于描述注解的适用范围
@Retention:表示需要在什么级别保存住是信息,用于描述注解的生命周期
(source(源代码) < class < runtime(运行时))
@Document:说明注解包含在javadoc(文档)中
@Inherited:说明子类可以继承父类的该注解
- Target
target 源码有个 ElementType[] value();
点开看里面的参数
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Formal parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE,
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE
}
所以传值的时候可以很多值
- @Retention(RetentionPolicy.RUNTIME)
- 格式:
@interface myAnnotation{
//注解的参数:参数类型+参数名(), 这不是方法
参数类型+参数名();
}
- 注意
@interface 自动继承java.lang.annotation.Annotation接口
@interface声明一个注解; public @interface 注解名{定义内容}
其中每一个方法实际是声明了一个配置参数
方法的名称就是参数的名称
可以通过default声明参数的默认值
如果只有一个参数成员,参数名为value(不成名的规定)
@interface myAnnotation{
String value();
}
注解元素必须要有值,定义注解元素时,经常使用空字符串,0作为默认值
如果默认值为为-1代表不存在
@Target(value = {ElementType.METHOD, ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@interface myAnnotation{
// 注解的参数:参数类型+参数名(), 这不是方法
String name() default "";
int age() default 0;
// 如果默认值为为-1代表不存在
int id() default -1;
}
- 使用
//如果没有默认值,我们必须给注解赋值
@myAnnotation(name = "jz")
public void test(){
}
二, 反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
动态语言:
在运行时可以改变结构的语言:例如新的函数,对象等
,通俗而言就是在运行时代码可以根据某些条件改变自生结构,主要的动态语言:C#,JavaScript
静态语言:
运行时不可以改变结构的语言,像java, c++, c
但java可以称为准动态语言,可以通过反射(reflection)机制获得类似的动态语言特性
Reflection 是java视为动态语言的关键,允许程序借助Refection API取得 任何类的内部信息,并操作属性及其方法
正常方式:引入包名-》new实例化-》获得对象
反射方式:实例化对象-》getClass()-》得到完整的包名称
class类
我们在使用反射时,需要先获得我们需要的类,而java.lang.Class这个类必不可少,他十分特殊,用来表示java中类型 (class/interface/enum/annotation/primitive type/void)本身。
一个类在内存中只有一个Class对象,类被加载后,类的整个结构都会封装在Class对象中
当一个class被加载,或当加载器(class loader)的defineClass()被 JVM调用,JVM 便自动产生一个Class 对象。
类反射组成:由于反射最终也必须有类参与,因此反射的组成一般有下面几个方面组成:
1.java.lang.Class.java:类对象;
2.java.lang.reflect.Constructor.java:类的构造器对象;
3.java.lang.reflect.Method.java:类的方法对象;
4.java.lang.reflect.Field.java:类的属性对象;
获取class类的对象
- 通过对象获得,Class c1 = person.getClass();
- 通过forName获得 Class c2 = Class.forName(“com.jiu.fanshe.Student”); 括号里面是类所在的包对应位置
- 类名.class Class c3 = Student.class;
- 内置对象可以通过包装类的type属性获得 Class c4 = Integer.TYPE;
package com.jiu.fanshe;
public class chuangjian {
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Student("张三");
// 通过对象获得
Class c1 = person.getClass();
System.out.println("c1 " + c1.hashCode());
// 通过forName获得
Class c2 = Class.forName("com.jiu.fanshe.Student");
System.out.println("c2 " + c2.hashCode());
// 类名.class
Class c3 = Student.class;
System.out.println("c3 " + c3.hashCode());
// 内置对象可以通过包装类的type属性获得
Class c4 = Integer.TYPE;
System.out.println("c4 " + c4);
}
}
class Person{
String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Student extends Person{
Student(String name){
super(name);
}
}
一个类在内存中只有一个Class对象:上面获取student类的Class对象,打印hashcode,3种方式获取到的是同一个
获取属性,方法等
public class chuangjian {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Person person = new Student("张三");
// 通过对象获得
Class c1 = person.getClass();
System.out.println("c1 " + c1.hashCode());
//获取该类的所有public字段,包括父类的
java.lang.reflect.Field[] fields = c1.getFields();
//根据字段名获取该类的public字段
java.lang.reflect.Field field = c1.getField("age");
for (java.lang.reflect.Field field1 : fields) {
System.out.println("public字段" + field1);
}
//找到全部的属性
fields=c1.getDeclaredFields();
for (java.lang.reflect.Field field1 : fields) {
System.out.println("全部的属性" + field1);
}
System.out.println("fields " + fields);
//获取该类的所有字段,不包括父类(仅自定义)
java.lang.reflect.Field[] fields1 = c1.getDeclaredFields();
//根据字段名获取该类的字段
java.lang.reflect.Field field1 = c1.getDeclaredField("age");
for (Field fields11 : fields1) {
System.out.println("所有字段" + fields11);
}
}
}
class Person{
String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Student extends Person{
public int age;
private int id;
Student(String name){
super(name);
}
}
这里是引用getFields()与getDeclaredFields()区别:
getFields()只能访问类中声明为公有的字段,私有的字段它无法访问,能访问从其它类继承来的公有方法.
getDeclaredFields()能访问类中所有的字段,与public,private,protect无关,不能访问从其它类继承来的方法
getMethods()与getDeclaredMethods()区别:
getMethods()只能访问类中声明为公有的方法,能访问从其它类继承来的公有方法.
getDeclaredFields()能访问类中所有的字段,与public,private,protect无关,不能访问从其它类继承来的方法
getConstructors()与getDeclaredConstructors()区别:
getConstructors()只能访问类中声明为public的构造函数.
getDeclaredConstructors()能访问类中所有的构造函数,与public,private,protect无关
获取属性方法后操作
- 动态创建对象
通过newInstance创建对象,类必须有一个无参构造,有足够访问权限
通过获得构造器创建
- 通过反射调用类的方法
- 反射操作属性
- …
public class CreatObj {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//获取类的对象
Class user = User.class;
//通过newInstance创建对象,类必须有一个无参构造,有足够访问权限
User user1 = (User)user.newInstance();//调用无参构造方法
System.out.println("user1 " + user1);
//通过获得构造器创建
Constructor constructor = user.getDeclaredConstructor(String.class, int.class, int.class);
User user2 = (User) constructor.newInstance("jz", 20, 11);
System.out.println("user2 " + user2);
//通过反射调用类的方法
User user3 = user1;
Method setName = user.getDeclaredMethod("setName", String.class);
//invoke激活,没有返回值就返回null,原方法是private 要开启可访问性
setName.invoke(user3, "jz");
System.out.println("user3 " + user3);
//反射操作属性
User user4 = (User) user.newInstance();
Field name = user.getDeclaredField("name");
//由于name属性private,不能访问没有权限,不能直接操作私有属性
//开启可访问性,不开启报错
name.setAccessible(true);
name.set(user4, "jz");
System.out.println("user4 " + user4);
}
}
class User{
private String name;
private int age;
private int id;
public User() {
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", id=" + id +
'}';
}
public User(String name, int age, int id) {
this.name = name;
this.age = age;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
注解反射实现简单orm
- 新建实体类student
class Student2{
private int id;
private int age;
private String name;
@Override
public String toString() {
return "Student2{" +
"id=" + id +
", age=" + age +
", 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;
}
public Student2() {
}
public Student2(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
}
- 自定义注解
//类名注解,数据库表名
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableName{
String value();
}
//属性注解,数据库字段
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Field{
String colName();
String type();
int length();
}
- 添加注解
@TableName(value = "Student")
class Student2{
@Field(colName = "id", type = "int", length = 10)
private int id;
@Field(colName = "age", type = "int", length = 10)
private int age;
@Field(colName = "name", type = "varchar", length = 10)
private String name;
- 实现
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c = Class.forName("com.jiu.fanshe.Student2");
//通过反射返回类上的注解
Annotation[] annotations = c.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println("@:" + annotation);
}
//获得注解value的值
TableName tableName = (TableName) c.getAnnotation(TableName.class);
String value = tableName.value();
System.out.println(value);
//获得类指定注解
java.lang.reflect.Field name = c.getDeclaredField("name");
Field field = name.getAnnotation(Field.class);
System.out.println(field.colName());
System.out.println(field.type());
System.out.println(field.length());
java.lang.reflect.Field[] fields = c.getDeclaredFields();
//拼接
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("create table " + value + "(\n");
for (java.lang.reflect.Field field1 : fields) {
Field field1Annotation = field1.getAnnotation(Field.class);
System.out.println(field1Annotation.colName());
System.out.println(field1Annotation.type());
System.out.println(field1Annotation.length());
stringBuffer.append(field1Annotation.colName() + " " + field1Annotation.type() + " (" + field1Annotation.length() + ") NOT NULL\n,");
}
stringBuffer.append("\b)");
System.out.println(stringBuffer);
}