1、注解(Annotation)
一些方法加了一杠表示不推荐使用,但是也能用
写代码时标了黄块的代码体就是警告
1.1注解
-
注解(Annotation)——用 @ 符号标示
不是程序本身,可以对程序作出解释(这一点与注释(comment)没什么区别)
可以被其他程序(比如:编译器)读取
通过反射机制编程实现对辅助信息数据的访问
1.2内置注解
-
内置注解(3个)
package annotation; import java.util.ArrayList; import java.util.List; //内置注解 public class TestD1 extends Object{ //@Override 重写的注解 @Override public String toString() { return super.toString(); } //Deprecated 不推荐程序员使用,但是可以使用,或者存在更好的方式 @Deprecated public static void test(){ System.out.println("Deprecated"); } //SuppressWarnings 镇压警告,既可以放在方法上,也可以放在类和构造器上面 @SuppressWarnings(value = "All") //注解只有一个值时,可以把value去掉 public void test02(){ List list = new ArrayList<>(); } public static void main(String[] args) { test(); } }
1.3元注解
元注解(注解其他注解,4个meta-annotation)
package annotation;
import java.lang.annotation.*;
//测试元注解
@MyAnnotation
public class TestD2 {
public void test(){
}
}
//定义一个注解(随便打开一个注解照着写)
//Target 表示我们的注解可以用在那些方面(进去后发现需要定义参数)
@Target(value = {ElementType.METHOD,ElementType.TYPE}) //用在ElementType.METHOD方法和ElementType.TYPE类上
//Retention 表示我们的注解在那些地方还有效
//runtime > class > sources(一般自定义都写在runtime)
@Retention(value = RetentionPolicy.RUNTIME)
//Documented 表示是否将我们的注解生成在JAVAdoc中
@Documented
//Inherited 子类可以继承父类的注解
@Inherited
@interface MyAnnotation{
}
1.4自定义注解(@interface)
package annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//自定义注解
public class TestD3 {
//注解可以显示赋值,如果没有赋值,我们就必须给注解赋值
@MyAnnotation2(age = 18,name = "yiyi")
public void test(){
}
@MyAnnotation3("erer") //默认value命名,value就可以不写
public void test2(){}
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
//注解的参数:参数类型 + 参数名()+默认; 注解可以显示赋值,如果没有赋值,我们就必须给注解赋值(默认)
String name() default "";
int age(); //没有给默认可以直接 @MyAnnotation2(age = 18,name = "yiyi")
int id() default -1;//如果默认为-1表示不存在
String[] schools() default {"奥运比赛","洛杉矶"}; //String[]数组
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3{
String value();//如果只有一个参数,建议使用value命名
}
2、反射(Reflection)
2.1反射
-
动态语言
运行时可以改变结构的语言 JavaScript
-
静态语言
运行时不可以改变结构的语言 java
java是准动态语言,可以通过反射机制获取类似动态语言特性
-
反射
优点:可以实现动态创建对象和编译,体现很大的灵活性
缺点:对性能有影响(减慢)
2.2获得反射对象
1.一个类在内存中只有一个class对象
2.一个类被加载后,类的整个结构都会被封装在Class结构中
package reflection;
//什么是反射
public class TestF1 {
public static void main(String[] args) throws ClassNotFoundException {
//通过反射获得类的Class对象
Class c1 = Class.forName("reflection.TestF1");
System.out.println(c1);
Class c2 = Class.forName("reflection.TestF1");
Class c3 = Class.forName("reflection.TestF1");
Class c4 = Class.forName("reflection.TestF1");
//如果hashcode相同,就说明是同一个class
/*
1.一个类在内存中只有一个class对象
2.一个类被加载后,类的整个结构都会被封装在Class结构中
*/
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
System.out.println(c4.hashCode());
}
}
//实体类 :pojo entity(属性会与数据库映射)
class User{
private String name;
private int id;
private int age;
public User() {
}
public User(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
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;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
'}';
}
}
2.2.1得到Class类的几种方式
package reflection;
//测试class类的创建方式有那些
public class TestF2 {
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Student();
System.out.println("这个人是:"+person.name);
//方式一:通过对象获得
Class c1 = person.getClass();
System.out.println(c1.hashCode());
//方式二:forname获得
Class c2 = Class.forName("reflection.TestF2");
System.out.println(c2.hashCode());
//方式三:通过类名.class获得
Class c3 = Student.class;
System.out.println(c3.hashCode());
//方式四:基本内置类型的包装类都有一个Type属性(有限制)
Class c4 = Integer.TYPE;
System.out.println(c4);
//获得父类的类型
Class c5 = c1.getSuperclass();
System.out.println(c5);
}
}
class Person{
public String name; //若果是private修饰,需要加set/get,public修饰不用
public Person() {
}
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
class Student extends Person{
public Student(){
this.name = "学生";
}
}
class Teacher extends Person{
public Teacher(){
this.name = "老师";
}
}
2.2.2所有类型的class对象
package reflection;
import javax.xml.bind.Element;
//按住Alt键可以复制多行
//所有类型的Class对象
public class TestF3 {
public static void main(String[] args) {
Class c1 = Object.class; // 类
Class c2 = Comparable.class; //接口
Class c3 = String[].class; //一维数组
Class c4 = Override.class; //注解
Class c5 = int[][].class; //二维数组
Class c6 = Element.class; //枚举
Class c7 = Integer.class; //基本数据类型
Class c8 = void.class; //void
Class c9 = Class.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
int[] a = new int[10];
int[] b = new int[100];
System.out.println(a.getClass().hashCode());
System.out.println(b.getClass().hashCode());
}
}
2.3类加载内存分析
2.3.1类加载内存分析
package reflection;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
/*类加载内存分析
1.加载到内存产生类对应的class对象
2.链接,链接结束后m=0 注意:所有的常量和静态变量在静态链接阶段就在赋值
3.初始化
<clinit>(){
System.out.println("A类静态代码块的初始化");
m = 300;
m = 100;
}
m =100
*/
public class TestF4 {
public static void main(String[] args) {
A a = new A();
System.out.println(A.m);
}
}
class A{
static{
System.out.println("A类静态代码块的初始化");
m = 300;
}
static int m = 100;
public A(){
System.out.println("A类的无参构造器初始化");
}
}
2.3.2分析类初始化
- 类的主动引用(一定会发生类的初始化)
- 类的被动应用(不会发生类的初始化)
package reflection;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
//测试类什么时候会被初始化
public class TestD5 {
static {
System.out.println("Main类被加载");
}
public static void main(String[] args) throws ClassNotFoundException {
//1.主动引用 new(new子类会先主动引用父类)
//Son son = new Son();
//2.反射也会产生主动引用(反射子类会先主动引用父类)
//Class.forName("reflection.Son");
//不会产生类的引用方法
//1.子类调用父类的静态方法或者变量
//System.out.println(Son.b);
//2.通过数组也不会加载类
//Son[] array = new Son[5];
//3.final常量池里的常量——所有的常量和静态变量在静态链接阶段就在赋值
System.out.println(Son.M);
}
}
class Father{
static int b = 2;
static {
System.out.println("父类被加载");
}
}
class Son extends Father{
static{
System.out.println("子类被加载");
m = 300;
}
static int m = 100;
static final int M = 1;
}
2.4类加载器的作用
-
引导类加载器:负载java平台核心库
-
扩展类加载器:jre/lib/ext目录下的jar包装入工作库
-
系统类加载器:classpath/path目录下的类或者jar包装入工作,是最常用的加载器
package reflection;
public class TestF5 {
public static void main(String[] args) throws ClassNotFoundException {
//获取 系统类的加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
//获取系统类加载器的父类加载器-->扩展类加载器
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent);
//获取扩展类加载器的父类加载器-->根类加载器(C/C++)
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);
//测试当前类是那个加载器加载的(系统类加载器)
ClassLoader classLoader = Class.forName("reflection.TestF5").getClassLoader();
System.out.println(classLoader);
//测试JDK内部的类是谁加载的(根加载器)
classLoader = Class.forName("java.lang.Object").getClassLoader();
System.out.println(classLoader);
//如何获得系统类加载器可以加载的路径
System.out.println(System.getProperty("java.class.path"));
/*
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\charsets.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\deploy.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\ext\access-bridge-32.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\ext\cldrdata.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\ext\dnsns.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\ext\jaccess.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\ext\jfxrt.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\ext\localedata.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\ext\nashorn.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\ext\sunec.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\ext\sunjce_provider.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\ext\sunmscapi.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\ext\sunpkcs11.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\ext\zipfs.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\javaws.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\jce.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\jfr.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\jfxswt.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\jsse.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\management-agent.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\plugin.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\resources.jar;
C:\Program Files (x86)\Java\jdk1.8.0_191\jre\lib\rt.jar;
D:\Java-Code\Process\Process6\process6\out\production\kuang2;
D:\Idea\IntelliJ IDEA 2024.1.4\lib\idea_rt.jar
*/
//双亲类委派机制——一级一级网上找(保证安全性)
}
}
3、获取
3.1获取类的信息
package get;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
//获取类的信息
public class TestG1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class c1 = Class.forName("reflection.User");
//获得类的名字
System.out.println(c1.getName());//获得包名+类名
System.out.println(c1.getSimpleName());//获得类名
//获得类的属性
System.out.println("=======================================");
Field[] fields = c1.getFields();//有没有s是一个属性和一堆属性的区别
//只能找到public属性
fields = c1.getDeclaredFields();
//可以找到全部的属性
for(Field field : fields){ //field.for生成,打印这些属性
System.out.println(field);
}
Field names = c1.getDeclaredField("name");
//获得指定的属性
System.out.println(names);
//获得类的方法
System.out.println("==========================");
Method[] methods = c1.getMethods();
//获取本类及其父类的全部public方法
for (Method method : methods) {
System.out.println("正常的:"+method);
}
methods = c1.getDeclaredMethods();
//获得本类的所有方法,没有父类
for (Method method : methods) {
System.out.println("getDeclaredMethods:"+method);
}
//获得指定方法
System.out.println("============================================");
Method getname = c1.getMethod("getName",null);
Method setname = c1.getMethod("setName",String.class);//setname及其所需参数类型
System.out.println(getname);
System.out.println(setname);
//获得指定的构造器
System.out.println("===============================");
Constructor[] constructors = c1.getConstructors();
for (Constructor constructor : constructors) {
System.out.println("##"+constructor);
}
constructors = c1.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
//获得指定的构造器
Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class,int.class);
System.out.println("指定"+declaredConstructor);
}
}
3.2通过反射创建对象(User不是公共的报错——没有解决)
package get;
import reflection.User;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
//动态的创建对象,通过反射
//一直报错,不理解为什么一直说User不是公共的,不能用,但老师的能用
public class getG2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//获得Class对象
Class c1 = Class.forName("reflection.User");
//构造一个对象
//User user = (User)c1.newInstance();//本质是调用了类得无参构造器
//System.out.println(user);
/* 这里不理解为什么一直报错
//通过构造器创建对象
Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
User user2 = (User)constructor.newInstance("小胖", 001, 18);
System.out.println(user2);
*/
}
}