Java-Day018

未曾想努力的活着只为了成为一个普通人

  • 反射
    • 反射的介绍
    • 获取Class
    • 获取类的修饰符
    • 创建对象
    • 父类与接口
    • 属性和方法
    • 数组
    • 类加载器
  • 注解
    • 注解的介绍
    • 注解的分类
    • 内置注解
      • @Override
      • @Deprecated
      • @SuppressWarnings
    • 自定义注解
      • 定义
      • 元注解
      • 定义注解格式
      • 注解参数(方法)

一、反射

1、反射的介绍

“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”,如Python,Ruby是动态语言;显然C++,Java,C#不是动态语言,但是JAVA有着一个非常突出的动态相关机制:Reflflection。JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

反射机制可以实现的功能

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时调用任意一个对象的方法
  • 生成动态代理

2、获取Class

所有类的对象其实都是Class的实例

Class对象就是,编译后的字节码文件在内存中的对象

Class对象的创价有三种方式

2.1、通过对象获取

Class clz = new String().getClass();

2.2、通过类获取

Class clz = String.class;

2.3、Class.forName获取

Class clz = Class.forName("java.lang.String");

获取自定义类的Class

public class Student {
    
    
	private String naem;
	public int age;
	
	
	public Student() {
    
    
		super();
	}
	public Student(String naem, int age) {
    
    
		super();
		this.naem = naem;
		this.age = age;
	}
}
Class clz = Class.forName("cn.yanghuisen.test.Student");

这种方式会抛出一个异常,需要自己处理


3、获取类的修饰符(getModifiers)

getModifiers方法获取类的修饰符,返回一个int类型

public class Test {
    
    
	public static void main(String[] args) throws Exception {
    
    
		Class clz = Class.forName("cn.yanghuisen.test.Student");
		int i = clz.getModifiers();		// 获取类的修饰符
		System.out.println(i);
	}
}
运行结果
1

1代表是public修饰

设置 修饰符
0 default
1 public
2 private
4 protected

可以通过Modifier.toString()方法获取对象数值的修饰符

public class Test {
    
    
	public static void main(String[] args) throws Exception {
    
    
		Class clz = Class.forName("cn.yanghuisen.test.Student");
		int i = clz.getModifiers();		// 获取类的修饰符
		System.out.println(Modifier.toString(i));
		System.out.println(Modifier.toString(0));
		System.out.println(Modifier.toString(2));
		System.out.println(Modifier.toString(4));
	}
}
运行结果
public

private
protected

Tips:第二行空行为Default


4、创建对象

4.1、获取构造器创建对象

4.1.1、无参构造器

public class Test2 {
    
    
	public static void main(String[] args) throws Exception {
    
    
		Class clz = Class.forName("cn.yanghuisen.test.Student");
		Constructor<Student> con = clz.getConstructor();	// 获取一个无参构造器
		Student student = con.newInstance();			// 创建对象
		System.out.println(student);
	}
}
运行结果
Student [name=null, age=0]

4.1.2、带参构造器

public class Test2 {
    
    
	public static void main(String[] args) throws Exception {
    
    
		Class clz = Class.forName("cn.yanghuisen.test.Student");
		Constructor<Student> con = clz.getConstructor(String.class,int.class);	// 获取一个带参构造器
		Student student = con.newInstance("张三",20);			// 创建对象
		System.out.println(student);
	}
}
运行结果
Student [name=张三, age=20]

4.1.3、构造器数组

public class Test2 {
    
    
	public static void main(String[] args) throws Exception {
    
    
		Class clz = Class.forName("cn.yanghuisen.test.Student");
		Constructor<Student>[]  cons = clz.getConstructors();	// 获取构造器数组
		for(Constructor c:cons) {
    
    		// 遍历一下,确认构造器顺序
			System.out.println(c);
		}
		Student student1 = cons[0].newInstance();			// 创建对象
		Student student2 = cons[1].newInstance("张三",20);			// 创建对象
		System.out.println(student1);
		System.out.println(student2);
	}
}
运行结果
public cn.yanghuisen.test.Student()
public cn.yanghuisen.test.Student(java.lang.String,int)
Student [name=null, age=0]
Student [name=张三, age=20]

获取构造器数组,然后遍历以下构造器数组,确定以下构造器在数组中的排列顺序

4.1.4、newInstance

public class Test2 {
    
    
	public static void main(String[] args) throws Exception {
    
    
		Class clz = Class.forName("cn.yanghuisen.test.Student");
		Student student = (Student) clz.newInstance();
		System.out.println(student);
	}
}
运行结果
Student [name=null, age=0]

newInstance是调用的无参构造器,如果无参空构造器不存在,则会出现异常


5、父类与接口

public class Test2 {
    
    
	public static void main(String[] args) throws Exception {
    
    
		Class clz = Class.forName("cn.yanghuisen.test.Student");
		System.out.println(clz.getSuperclass());		// 返回父类的Class
		System.out.println(Arrays.toString(clz.getInterfaces()));	// 获取接口,返回的是一个Class数组
	}
}
结果
class java.lang.Object
[]

因为没有实现任何接口,所以第二行是[]


6、属性与方法

也可以通过反射获取类中的属性和方法,包括父类和接口中的

6.1、属性

6.1.1、获取指定属性

public class Test2 {
	public static void main(String[] args) throws Exception {
		Class clz = Class.forName("cn.yanghuisen.test.Student");
		Field field = clz.getDeclaredField("name");		// 获取本类中的指定属性(包含private)
		System.out.println(field);
		System.out.println(field.getName());		// 获取属性名
		System.out.println(field.getType());		// 获取属性类型
		field = clz.getField("age");		// 获取本类或父类中的public修饰的指定的属性
		field = clz.getField("sex");
	}
}
运行结果
private java.lang.String cn.yanghuisen.test.Student.name
name
class java.lang.String

6.1.2、获取属性数组

public class Test2 {
    
    
	public static void main(String[] args) throws Exception {
    
    
		Class clz = Class.forName("cn.yanghuisen.test.Student");
		Field[] fields = clz.getDeclaredFields();		// 获取本类中的所有属性(包含private)
		System.out.println(Arrays.toString(fields));
		fields = clz.getFields();	// 获取本类或父类中修饰为public的属性
		System.out.println(Arrays.toString(fields));
	}
}
运行结果
[private java.lang.String cn.yanghuisen.test.Student.name, public int cn.yanghuisen.test.Student.age]
[public int cn.yanghuisen.test.Student.age, public boolean cn.yanghuisen.test.Person.sex]

6.1.3、修改属性值

public class Test2 {
    
    
	public static void main(String[] args) throws Exception {
    
    
		Class clz = Class.forName("cn.yanghuisen.test.Student");
		Field field = clz.getDeclaredField("name");		// 获取本类中的指定属性(包含private)
		field.setAccessible(true);		// 允许反射修改private的属性,如果指定的属性是public的可以不用设置
		Student student = (Student) clz.newInstance();
		field.set(student, "张三");
		System.out.println(student);
	}
}
运行结果
Student [naem=张三, age=0]

6.2、方法

6.2.1、获取指定方法

public class Test2 {
    
    
	public static void main(String[] args) throws Exception {
    
    
		Class clz = Class.forName("cn.yanghuisen.test.Student");
		Method method = clz.getDeclaredMethod("setName",String.class);		// 获取本类中的指定的方法
		System.out.println(method.getName());		// 获取方法名
		System.out.println(method.getParameterCount());		// 获取方法的参数数量
		System.out.println(method.getReturnType());		// 获取方法的返回值类型
		method = clz.getMethod("setSex",boolean.class);		// 获取public的方法(包含父类和接口)
	}
}
运行结果
setName
1
void

6.2.2、获取方法数组

public class Test2 {
    
    
	public static void main(String[] args) throws Exception {
    
    
		Class clz = Class.forName("cn.yanghuisen.test.Student");
		Method[] methods = clz.getDeclaredMethods();		// 获取本类中的所有的方法
		Arrays.asList(methods).stream().forEach(System.out::println);
		methods = clz.getMethods();		// 获取public的所有的方法(包含父类和接口)
		Arrays.asList(methods).stream().forEach(System.out::println);
	}
}
运行结果
public java.lang.String cn.yanghuisen.test.Student.toString()
public java.lang.String cn.yanghuisen.test.Student.getName()
public void cn.yanghuisen.test.Student.setName(java.lang.String)
public void cn.yanghuisen.test.Student.setAge(int)
public int cn.yanghuisen.test.Student.getAge()
public java.lang.String cn.yanghuisen.test.Student.toString()
public java.lang.String cn.yanghuisen.test.Student.getName()
public void cn.yanghuisen.test.Student.setName(java.lang.String)
public void cn.yanghuisen.test.Student.setAge(int)
public int cn.yanghuisen.test.Student.getAge()
public boolean cn.yanghuisen.test.Person.isSex()
public void cn.yanghuisen.test.Person.setSex(boolean)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

6.2.3、调用方法

public class Test2 {
    
    
	public static void main(String[] args) throws Exception {
    
    
		Class clz = Class.forName("cn.yanghuisen.test.Student");
		Method method = clz.getDeclaredMethod("setName",String.class);		// 获取本类中的指定的方法
		Student student = (Student) clz.newInstance();		// 创建对象
		method.invoke(student, "张三");
		System.out.println(student);
	}
}
运行结果
Student [naem=张三, age=0]

7、数组

public class Test3 {
    
    
	public static void main(String[] args) {
    
    
		Object obj = Array.newInstance(int.class, 10);		// 创建一个int类型的数组,长度为10
		System.out.println(Array.getLength(obj));		// 获取数组长度
		Array.set(obj, 6, 6);				// 设置指定索引位置的值
		System.out.println(Array.get(obj, 0));			// 获取指定索引位置的值
		System.out.println(Arrays.toString((int[])obj));
	}
}
运行结果
10
0
[0, 0, 0, 0, 0, 0, 6, 0, 0, 0]

8、类加载器

在java中有三种类类加载器:

  • Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。
  • Extension ClassLoader 用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类
  • AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。
public static void main(String[] args) throws Exception {
    
     
    System.out.println("类加载器"+ClassLoader.class.getClassLoader().getClass().getName());
}

类的生命周期:

在一个类编译完成之后,下一步就需要开始使用类,如果要使用一个类,肯定离不开JVM。在程序执行中JVM通过装载链接初始化这3个步骤完成。

类的装载是通过类加载器完成的,加载器将.class文件的二进制文件装入JVM的方法区,并且在堆区创建描述这个类的java.lang.Class对象。用来封装数据。 但是同一个类只会被类装载器装载一次。

链接就是把二进制数据组装为可以运行的状态。链接分为校验,准备,解析这3个阶段

  1. 校验一般用来确认此二进制文件是否适合当前的JVM(版本),
  2. 准备就是为静态成员分配内存空间。并设置默认值
  3. 解析指的是转换常量池中的代码作为直接引用的过程,直到所有的符号引用都可以被运行程序使用(建立完整的对应关系)完成之后,类型也就完成了初始化,初始化之后类的对象就可以正常使用了,直到一个对象不再使用之后,将被垃圾回收。释放空间。当没有任何引用指向Class对象时就会被卸载,结束类的生命周期

二、注解

1、注解的介绍

注解是Java 1.5引入的,目前已被广泛应用于各种Java框架,如Hibernate,Jersey,Spring。注解相当于是一种嵌入在程序中的元数据,可以使用注解解析工具或编译器对其进行解析,也可以指定注解在编译期或运行期有效。在注解诞生之前,程序的元数据存在的形式仅限于java注释或javadoc,但注解可以提供更多功能,它不仅包含元数据,还能作用于运行期,注解解析器能够使用注解决定处理流程。

**Annotation(****注解)**就是Java提供了一种元程序中的元素关联任何信息和任何元数据 (metadata)的途径和方法。

Annotation是一个接口,程序可以通过反射来获取指定程序元素的Annotation对象,然后通过Annotation对象来获取注解里面的元数据。注解API非常强大,被广泛应用于各种Java框架。

元数据:描述数据的数据


2、注解的分类

2.1、根据注解参数的个数

  • 标记注解:一个没有成员定义的Annotation类型称为标记注解。
  • 单值注解:只有一个值。
  • 完整注解:拥有多个值。

2.2、根据注解使用方法和用途

  • JDK内置系统注解
  • 元注解
  • 自定义注解

3、内置注解

Java中内置了三个标准注解,定义在Java.lang中

3.1、@Override

标记重写了父类的方法

@Override
public String toString() {
    
    
    return "Student [naem=" + name + ", age=" + age + "]";
}

3.2、@Deprecated

标记已过时的方法

public class Test4 {
    
    
	
	public static void main(String[] args) {
    
    
		a1();
	}
	
	@Deprecated
	static void a1() {
    
    
		System.out.println("啊哈哈");
	}
}

被标记@Deprecated的方法不会被停用,可以正常使用,只是不建议使用

3.3、SuppressWarnings

抑制编辑器警告信息

@SuppressWarnings("all")
public class Test4 {
    
    

	public static void main(String[] args) {
    
    
		int a = 0;
	}
	
}
  • all to suppress all warnings (抑制所有警告)
  • boxing to suppress warnings relative to boxing/unboxing operations(抑制装箱、拆箱操作时候的警告)
  • cast to suppress warnings relative to cast operations (抑制映射相关的警告)
  • dep-ann to suppress warnings relative to deprecated annotation(抑制启用注释的警告)
  • deprecation to suppress warnings relative to deprecation(抑制过期方法警告)
  • fallthrough to suppress warnings relative to missing breaks in switch statements(抑制确在switch中缺失breaks的警告)
  • finally to suppress warnings relative to finally block that don’t return (抑制finally模块没有返回的警告)
  • hiding to suppress warnings relative to locals that hide variable()
  • incomplete-switch to suppress warnings relative to missing entries in a switch statement (enum case)(忽略没有完整的switch语句)
  • nls to suppress warnings relative to non-nls string literals(忽略非nls格式的字符)
  • null to suppress warnings relative to null analysis(忽略对null的操作)
  • rawtypes to suppress warnings relative to un-specific types when using generics on class params(使用generics时忽略没有指定相应的类型)
  • restriction to suppress warnings relative to usage of discouraged or forbidden references
  • serial to suppress warnings relative to missing serialVersionUID field for a serializable class(忽略在serializable类中没有声明serialVersionUID变量)
  • static-access to suppress warnings relative to incorrect static access(抑制不正确的静态访问方式警告)
  • synthetic-access to suppress warnings relative to unoptimized access from inner classes(抑制子类没有按最优方法访问内部类的警告)
  • unchecked to suppress warnings relative to unchecked operations(抑制没有进行类型检查操作的警告)
  • unqualified-field-access to suppress warnings relative to field access unqualified (抑制没有权限访问的域的警告)
  • unused to suppress warnings relative to unused code (抑制没被使用过的代码的警告)

4、自定义注解

4.1、定义

public @interface A {
    
    
	
}

**@interface:**用来声明一个注解

4.2、元注解

元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它annotation类型作说明。Java5.0定义的元注解有四个,这些类型和它们所支持的类在ava.lang.annotation包中可以找到。

4.2.1、@Target

描述注解使用的范围

@Target({
    
    ElementType.METHOD,ElementType.FIELD,ElementType.TYPE})
public @interface A {
    
    
	
}

取值范围:

  • CONSTRUCTOR:用于描述构造器
  • FIELD:用于描述域
  • LOCAL_VARIABLE:用于描述局部变量
  • METHOD:用于描述方法
  • PACKAGE:用于描述包
  • PARAMETER:用于描述参数
  • TYPE:用于描述类、接口(包括注解类型) 或enum声明

4.2.2、@Retention

表示需要在什么级别保存该注解,用于描述注解的声明周期

@Retention(RetentionPolicy.RUNTIME)
@Target({
    
    ElementType.METHOD,ElementType.FIELD,ElementType.TYPE})
public @interface A {
    
    
	
}
  • SOURCE:在源文件中有效(即源文件保留)
  • CLASS:在class文件中有效(即class保留)
  • RUNTIME:在运行时有效(即运行时保留)

4.2.3、@Documented

该注解的元素应该被JavaDoc或类似工具文档化

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({
    
    ElementType.METHOD,ElementType.FIELD,ElementType.TYPE})
public @interface A {
    
    
	
}

4.2.4、Inherited

注解会被自动继承

@Inherited
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({
    
    ElementType.METHOD,ElementType.FIELD,ElementType.TYPE})
public @interface A {
    
    
	
}

4.3、定义注解格式

使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。

public @Interface 注解名{
    
    
	定义体
}

4.4、注解参数(方法)

注解里面的每一个方法实际上就是一个配置参数,其规则如下

  • 修饰符:只能用public或default这两个访问权限修饰符,默认会default。

  • 类型:注解参数只支持以下类型

    • 基本数据类型
    • String类型
    • Class类型
    • enum类型
    • Annotation类型

    TIPS:不支持自定义类型

  • 命名:对名字没有要求,如果只有一个参数成员,最好把参数名设置为“value”,后面加小括号

  • 参数:注解中的方法不能存在参数

  • 默认值:可以包含默认值,使用default声明

@Inherited
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({
    
    ElementType.METHOD,ElementType.FIELD,ElementType.TYPE})
public @interface A {
    
    
	
	// 数组
	public String[] values();
	// 单个值
	boolean flag();
	// 默认值
	public String ab() default "啊哈哈";
}
@A(values= {
    
    "张三","李四"},flag=true)
public class Test9 {
    
    

}

猜你喜欢

转载自blog.csdn.net/Asdzxc968/article/details/104769839
今日推荐