学习渠道:B站狂神说Java
注解
注解的分类
1.内置注解
@Override:java.lang.Override
表示一个方法声明要重写超类中的一个方法声明。
@Deprecated:java.lang.Deprecated
属性,类,表示过时的元素,通常它是有风险的,或者有更好的选择。
@SuppressWarnings:java.lang.SuppressWarnings
可以用在类或者方法,属性上用来使编译时的警告信息不显示它是有参数的例如:
@SuppressWarnings(“all”),@SuppressWarnings(“unchecked”),@SuppressWarnings({“uncheked”,“deprecation”})
2.元注解
元注解作用就是对于其他注解进行说明,这些注解可以再java.lang.annotation包中找到.
@Target:用于描述注解的使用范围(属性,方法,类)
@Retention:表示注解的生命周期(源码(SOURCE)<编译(CLASS)<运行时(RUNTIME))
@Document:说明该注解被包含在javadoc中
@Inherited:说明子类可以继承父类中的该注解
3.自定义注解
@interface 修饰的类就是注解,然后可以由元注解来标明使用的细节
注意:如果注解中只有一个参数且参数名为value时,在使用时可以不写参数名直接填参数。其他情况下有参数并且没有默认值是,使用必须填写参数名和参数内容。
元注解和自定义注解的使用例子
@Annotation1("a1")//value一个参数可以不写参数名
@Annotation2(name = "a2")//没有默认值的参数必须赋值
public class Annotation {
}
//元注解设置适用范围
@Target({ElementType.TYPE,ElementType.METHOD})
//元注解Retention 设置有效范围(源文件,编译,运行)
@Retention(RetentionPolicy.RUNTIME)
@interface Annotation1{ //写在类中的注解不能有public
//当注解只有一个参数且参数名为value时可以省略不写
String value();
}
@Target({ElementType.TYPE,ElementType.METHOD})
@interface Annotation2{
String name();
int age() default 18;
String[] students() default {"1","2"};
}
反射
动态语言和静态语言
动态语言是一类在运行时可以改变其结构的语言:例如新的函数,对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。简单的讲就是在运行时代码能够根据某些条件改变自身结构
主要的动态语言:object-C、C#、JavaScript、PHP、Python等
静态语言:运行时结构不可变的语言就是静态语言。比如Java、C、C++。
Java不是动态语言,但Java被称之为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制获得类似动态语言的特性。Java的动态性让编程的时候更加灵活。
Class类
加载完类之后在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了完整的类的结构信息。
Class本身就是一个类
Class对象只能有系统建立对象
一个加载类在JVM中只会有一个.class文件
一个Class对象对应的是一个加载到JVM的一个.class文件
每个类的实例都会记得自己是由哪个class类生成
通过Class可以完整的得到一个类中的所有被加载的结构(反射的核心)
Class类是Reflection的根源,针对任何你想动态加载、运行的类、唯有先获得相应的class对象
反射(Reflection)
反射是Java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。反射可以通过对象来获取Class类的完整结构。这个对象就是一面镜子,透过镜子看类结构所以称为反射。
Class类的常用方法
获取Class对象的方式
public class ReflectionTest {
public static void main(String[] args) throws ClassNotFoundException {
User u1 = new User();
Class c1 = u1.getClass();
Class c2 = Class.forName("reflection.User");
//类的实例化对象和Class静态方法获取的class对象是同一个class对象
//类在被加载时会生成唯一一个calss对象在堆中。
System.out.println(c1.hashCode());
System.out.println(c2.hashCode());
System.out.println("------------------------------------------------");
//获取class对象的方法
//通过类名直接获取
Class c3 = Studnet.class;
System.out.println("student的class:"+c3.hashCode());
//通过具体路径获取
Class c4 = Class.forName("reflection.Studnet");
System.out.println("student的class:"+c4.hashCode());
//通过具体的对象获取
Studnet studnet = new Studnet();
Class c5 = studnet.getClass();
System.out.println("student的class:"+c5.hashCode());
//JDK一些基本数据类型的包装类可以通过type直接获取
Class c6 = Integer.TYPE;
System.out.println("Integer包装类的class:"+c6);
//通过子类clss获取父类对象的class
Class c7 = c3.getSuperclass();
System.out.println("student的父类User的class:"+c7.hashCode());
Class cl1 = int.class;
Class cl2 = Integer.class;
System.out.println(cl1.hashCode());
System.out.println(cl2.hashCode());//结果是不一样
}
}
具体的一些常用方法
(下面的例子主要介绍了怎么通过class来获取类的结构)
class User{
private String name ;
private String id;
private int age;
public User() {
}
public User(String name, String id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
private User(Studnet a){
}
get.... set.....
}
public class Demo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class c1 = Class.forName("reflection.User");
String name1 = c1.getName();
System.out.println("带包名的名称"+name1);
String simpleName = c1.getSimpleName();
System.out.println("不带包名的名称"+simpleName);
/*
类的属性
*/
//获取类的属性
Field[] fields = c1.getFields();//获取类的public属性
for (Field field : fields) {
System.out.println(field);
}
fields = c1.getDeclaredFields();//获取类的所有属性
for (Field field : fields) {
System.out.println("所有属性"+field);
}
Field name = c1.getDeclaredField("name");//获取指定的属性包括私有的和公共的
System.out.println(name);
/*
类的方法
*/
Method[] methods = c1.getMethods();
for (Method method : methods) {
System.out.println("public修饰的方法包括父类的"+method);
}
methods = c1.getDeclaredMethods();
for (Method method : methods) {
System.out.println("自己类全部的方法"+method);
}
Method method = c1.getMethod("getName", null);
System.out.println(method);
method = c1.getDeclaredMethod("setName", String.class);
System.out.println(method);
/*
构造方法
*/
Constructor[] constructors = c1.getConstructors();//公共的构造方法
for (Constructor constructor : constructors) {
System.out.println("公共的构造方法"+constructor);
}
constructors = c1.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println("所有的构造方法"+constructor);
}
}
}
通过类的结构来创建类对象,调用方法,属性。
public class Demo1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
Class c1 = Class.forName("reflection.User");//获取class对象
Constructor constructor = c1.getDeclaredConstructor(String.class, String.class, int.class);//获取有参构造方法
User user = (User) constructor.newInstance("学习没个头", "001", 18);//执行有参构造方法
System.out.println(user);
User user1 = (User) c1.newInstance();//执行无参构造方法
user1.setName("学习头在哪");
Field id = c1.getDeclaredField("id");//获取id属性
id.setAccessible(true);
id.set(user1,"002");//指定对象来设置属性(需要属性权限为public若为私有的需要调用属性的setAccessible设置为true)
Method setAge = c1.getDeclaredMethod("setAge", int.class);//获取方法
setAge.setAccessible(true);
setAge.invoke(user1,19);//指定对象来设置使用方法(需要方法权限为public若为私有的需要调用方法的setAccessible设置为true)
System.out.println(user1);
}
}
setAccessible
这个是控制结构安全状态的方法,若是true则安全状态接触,可以操作private修饰的属性,方法,并且可以减少处理时间。若为false(默认)则private修饰的属性和方法不能通过结构进行操作。
性能
对象操作>不加安全状态的反射结构操作>加安全状态的接口操作。
还有class对象操作泛型,注解需要补充