泛型-注解-反射

目录

泛型

1.什么是泛型

2.为什么使用泛型

3.如何使用泛型

4.对象的引用传递和值传递

5.泛型通配符

6.泛型的限制

7.泛型接口

8.泛型方法

注解

1.什么是注解

2.注解的分类

3.预定义注解

4.自定义注解

5.元注解

6.自定义注解高级

反射

1.什么是反射

 2.如何获取反射类-Class

3.通过反射类获取相应的类对象

4.通过反射获取属性类对象

5.通过Field操作类中属性

6.通过反射获取方法类对象

6.1.Method类中常见的方法

7.通过反射获取构造方法对象

8.通过反射获取类上的注解

8.1.通过注解对象操作注解中相关的属性


泛型

1.什么是泛型

List<E>:这里的<E>就是泛型标志,Map<K,V>这里<K,V>也是泛型标记。

泛型:就是类再定义时无法确认类中成员的类型(属性,方法),而是类再创建时指定具体的数据类型。

2.为什么使用泛型

案例: 定义一个Point 类,要求如下

  1. 它的坐标值可以是整数。x=15,y=25

  2. 它的坐标值也可以都是小数: x=15.5 y=25.5

  3. 它的坐标值也可以都是字符串类型: x="北纬15度" y="东经258度"

Point.java

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Point {

    private Object x;
    private Object y; //因为Object是所有类的父类,而且多态,子类类型可以自动向父类类型转化

}
TestPoint.java
public class TestPoint {
    public static void main(String[] args) {

        //整数类型
        Point p1 = new Point(15,25);
        //小数类型
        Point p2 = new Point(15.5,25.5);
        //字符串类型
        Point p3 = new Point("北纬15度","东经258度");

        //字符串和整数类型
        Point p4 = new Point("x坐标65",85);
        String x = (String) p4.getX();
        //报错:java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
        //如果使用Object定义类中属性类型,那么可能再后期会出现数据类型安全问题。
        String y = (String) p4.getY();
    }
}

上面使用Object接受任意参数,可能会出现数据类型安全问题。如何解决上述问题,由于无法在类定义时确定类中成员的数据类型,所以可以使用泛型来解决数据类型安全问题

3.如何使用泛型

泛型可以解决数据类型的安全性问题,其主要原理是在类声明时通过一个标识表示类中某个属性的数据类型或者是某个方法的返回值及参数类型。这样在类声明或者实例化时只要指定好需要的类型即可。

语法:

public class 类名<T,E,B>{
 private T a;
 public T getA(){}
 public void setA(T t){}
}

修改上面案例:使用泛型来解决Point类的安全问题

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Point<T> {

    private T x;
    private T y; //因为Object是所有类的父类,而且多态,子类类型可以自动向父类类型转化

}


//=============================================================================

public class TestPoint {
    public static void main(String[] args) {

        //整数类型
        Point<Integer> p1 = new Point<>(15, 25);
        //小数类型
        Point<Double> p2 = new Point<>(15.5, 25.5);
        //字符串类型
        Point<String> p3 = new Point<>("北纬15度", "东经258度");

        String x = p3.getX();
        Integer x1 = p1.getX();//不会出现数据类型安全问题。
        // 注意: 泛型的类型必须指定为引用类型,不能使用基本类型【byte short int long float double boolean char】。--->包装类:Byte Short ...Integer .......Character
        //我们在创建泛型类对象时没有指定泛型:--它就是Object类型
        System.out.println(x + "===" + x1);
    }
}

4.对象的引用传递和值传递

基本类型的传递都是传递(参数改变不影响外部的参数)

引用传递,传递的是地址

案例:基本类型的传递都是值传递--参数的改变不影响外部的参数
public class Test01 {

    public static void main(String[] args) {
        int a = 20;
        fun(a);
        System.out.println("a==="+a); //20
    }

    //基本类型的传递都是值传递--参数的改变不影响外部的参数
    public static void fun(int a){
        a=15;
    }
}

案例:引用传递,传递的是地址

public class Test01 {

    public static void main(String[] args) {
        In i = new In();
        i.b=15;
        fun(i);
        System.out.println("b=="+i.b);//25

    }

    //引用传递,传递的是地址
    public static void fun(In i){
        i.b=25;
    }
}

class In{
    public int b;
}

5.泛型通配符<?>

在开发中对象的引用传递是最常见的,但是如果在泛型类的操作中,在进行引用传递时泛型类型必须匹才可以传递,否则是无法传递的。

案列:引用传递

public class Test {
    public static void main(String[] args) {

        Info<Integer> a = new Info<>(15);
        Info<String> a2 = new Info<>("abc");
        fun(a);
        fun(a2); //泛型的引用传递,要求数据类型匹配而且泛型也要匹配
    }

    //任意的泛型都可以传递过来 使用通配符?
    public static void fun(Info<?> info){
        info.show();
    }
}

class Info<T>{
    private T vat ;
    public void show(){
        System.out.println("vat===="+vat);
    }



    public Info() {
    }

    public Info(T vat) {
        this.vat = vat;
    }

    /**
     * 获取
     * @return vat
     */
    public T getVat() {
        return vat;
    }

    /**
     * 设置
     * @param vat
     */
    public void setVat(T vat) {
        this.vat = vat;
    }

    public String toString() {
        return "Info{vat = " + vat + "}";
    }
}

6.泛型的限制

在引用传递中,在泛型操作中也可以设置一个泛型对象的范围上限范围下限。范围上限使用extends关键字声明,表示参数化的类型可能是所指定的类型或者是此类型的子类,而范围下限使用super进行声明,表示参数化的类型可能是所指定的类型或者此类型的父类型。

语法:


public  void 方法名(Info<? extends Number> info){
    //传递参数的泛型必须是Number或者Number的子类
}

public  void 方法名(Info<? super Number> info){
    //传递参数的泛型必须是Number或者Number的父类
}
//案列:
public class Test04 {
    public static void main(String[] args) {
//        Info<Integer> a=new Info<>(15);
//        Info<String>  b=new Info<>("Hello");
//        Info<Number>  c=new Info<>(25.5);  //限定泛型的上线
//        fun2(a);
//        fun2(b);//泛型的引用传递,要求数据类型匹配而且泛型也要匹配。
//
//        fun2(c);
//
//        Info<Object> d=new Info<>(258);//限定泛型的下限
//        fun3(c);  //限定泛型的上线
//        fun3(a);
//        fun3(b);
//        fun3(d);

    }

    //限定泛型的上线:泛型的限制使用在方法的引用传递中。
    public static void fun2(Info<? extends Number> info){
        info.show();
    }
    //限定泛型的下限
    public static void fun3(Info<? super Number> info){
        info.show();
    }


    //任意的泛型都可以传递过来。 使用泛型通配符。?
    public static void fun(Info<?> info){
         info.show();
    }

}

class Info<T>{
     private T var;

    public Info(T var) {
        this.var = var;
    }

    public void show(){
        System.out.println("var==============="+var);
    }

    public T getVar() {
        return var;
    }

    public void setVar(T var) {
        this.var = var;
    }
}

7.泛型接口

List<E> ArrayList<E>

在JDK1.5之后,不仅可以声明泛型类,也可以声明泛型接口,声明泛型接口和声明泛型类的语法类似,也是在接口名称后面加上<T>,

格式如下:

[访问权限] interface 接口名称<泛型标识>{

                           

                        }

泛型接口的实现类的方式有两种:

(1)在创建类时也声明泛型而且该泛型的标识必须和接口的标识一致。

(2)在类实现泛型接口时,指明该泛型的数据类型。

案列:


public class Test05 {
}

interface  USB<T>{
    public void show(T t);
}
//在创建类时,也指定泛型要求必须和接口的泛型标志一致
class Upan<T> implements USB<T>{


    @Override
    public void show(T t) {
        
    }
}
class Shu  implements  USB<String>{

    @Override
    public void show(String s) {
        
    }
}



8.泛型方法

所有的泛型操作都是将整个类进行泛型化,但同样也可以在类中定义泛型化的方法。泛型方法的定义与其所在的类是否是泛型类是没有任何关系的,所在的类可以是泛型类,也可以不是泛型类

格式:

泛型方法: public <标志> 返回值 方法名(参数列表){}

案列:

public class Test05 {

    
    public static void main(String[] args) {
        Test05 t=new Test05();
        String hello = t.fun("hello");  //调用泛型方法
        Integer fun = t.fun(15);
    }

    //泛型方法: <T>在方法的返回值前面多了个泛型标志
    public <T> T fun(T t){
        System.out.println("结果为:"+t);
        return t;
    }
}

注解

1.什么是注解

注释: 注释给开发人员开的。对你的代码加以解释,程序编译后该注释不可见。

注解: 注解给程序看,该注解编译后依然存在。

@Controller @RequestMapping() ---Spring程序看的。

@Override JVM虚拟机看;重写特点:方法名要和父类被重写的方法一致,参数列表要一致,返回值要一致。访问修饰符不能小于父类访问修饰。抛出的异常不能大于父类异常。

如果注解不被解析,那么注解就没有任何意义。

2.注解的分类

1.预定义注解:----JDK自带的一些常用注解。(JDK能够识别的注解)
2.自定义注解-----我们自己定义的注解
3.元注解:------注解上使用的注解。

3.预定义注解

1. @Override: 表示方法重写,只要使用了该注解必须符合重写的规则
2. @Deprecated: 表示已过时。告诉调用者该方法已过时
2. @SuppressWarnings: 表示压制警告。
3. @FunctionInterface: 函数式接口注解。使用该注解表明接口中只能有一个抽象方法。

案例:


public class Test06 {

    public static void main(String[] args) {
        Son s=new Son();
        s.show();
    }
}
class Father{
    public void print(){
        System.out.println("这是father中的方法");
    }
}

class Son extends Father{

    @Override//检查该方法重写时是否符合重写规则
    public void print() {
        System.out.println("这是子类的方法");
    }

    @Deprecated //标记该方法过时,在调用该方法有个删除线
    public void show(){

    }
    public void showPrefect(){

    }
}
@SuppressWarnings(value = "all")  //表示压制警告
@SuppressWarnings(value = "all")  //表示压制警告
public class Test {
    public static void main(String[] args) {
        int a = 15 ;
    }
}

@FunctionInterface: 函数式接口注解。使用该注解表明接口中只能有一个抽象方法。

public class Test03 {
    public static void main(String[] args) {

    }
}
@FunctionalInterface //该接口中有且仅有一个抽象方法 1.8以后
interface Usb{
    public void show();
}

4.自定义注解

格式:

public @Interface 注解名{//
    //属性
}

案例:

public @interface My { //定义注解
}

@My  //在类上使用
class Hello{
    @My //在方法是使用
    public void show(@My int a){ //在参数中使用
        
    }

    @My //在属性上使用
    public String name;
}

自定义的注解默认对代码没有任何影响,如果想让注解有意义,必须解析该注解。可以结合反射,来解析这些注解。

@Controller注解是因为Spring框架解析了它 @Override JVM解析了它。

5.元注解

使用注解上的注解就是元注解

@Target:作用:表示该注解使用的范围。默认所有

  • TYPE,可以使用在类上
  • FIELD,使用在属性上
  • METHOD,使用在方法上
  • PARAMETER,使用在方法参数上
  • CONSTRUCTOR,使用在构造方法上
public class Test {
}
@Target(value = {ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
@interface My{

}

@My
class Hello{
    @My
    private String name;
    @My
    public void show(){}
    public void print(String name){}
}

@Retention:作用:表示该注解什么时候有效。默认SOURCE

  • SOURCE:源码时有效
  • CLASS:字节码时
  • RUNTIME:运行时有效。【采用最多】
public class Test {
    public static void main(String[] args) {
        Hello hello = new Hello();
    }
}
@Target(value = {ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
@Retention(value = RetentionPolicy.RUNTIME)
@interface My{

}

@My
class Hello{
    @My
    private String name;
    @My
    public void show(){}
    public void print(String name){}
}

@Documented:作用:在代码生成api文档时是否存在(显示)该注解

6.自定义注解高级

使用@GetMapping注解时可以有属性值:

格式:

@interface注解名{

数据类型 属性名();

}

数据类型可以是哪些类型?

基本数据类型,字符串类型,枚举类型,注解类型;以及上面这些类型的数组类型

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation {
    int age();//基本类型
    String name();//字符串类型
    MyEnum address();//枚举
    My my();//注解类型
    //上面类型的数组类型
    int[] ages();
    String[] names();
    MyEnum[] addresss();
    My[] mys();
}

如果属性定义好后,在使用该注解是需要指定属性的值

//如果属性为数组类型,给数组类型赋值时如果只有一个值,那么可以省了{}
// 如果该注解中只使用value属性,那么value属性名可以省略
@MyAnnotation(age = 15,name = "张三",address = MyEnum.BEIJING,my = @My,ages = {15,20,25},names = {"hello","666"},addresss = MyEnum.BEIJING,mys = @My)
@My(value = "good",name = "成龙")
public class Student {
    public void show(){
        System.out.println("hello");
    }
}



//============================================
@Target(ElementType.TYPE)
public @interface My {
    String value() default "hello===";  // 默认值
    String name() default  "王宝强";
}



//==============================================
public enum MyEnum {BEIJING
}

反射

1.什么是反射

反射是框架设计的灵魂!

什么是框架:

框架它是一种半成品,使用它时只需要填充自己的业务代码,作用是 提高开发效率。比如:springmvc  mybatis框架...

什么是反射:

  • 反射就是java在运行时,把类中成员(类的属性,方法,构造,注解) 抽取成其他类的过程
  • 把类中的成员封装到其他类对象的形式;再通过封装的类对象可以获取成员的信息

 2.如何获取反射类-Class

获取反射类的方式有三种:

第一种:Class.forName("类的全路径")            场景:spring<bean class="类全名">

第二种:类名.class                                          场景:session.getMapper(接口.class)

第三种:对象.getClass                                    场景:在知道类对象时可以使用

public class Test01 {
    public static void main(String[] args) throws ClassNotFoundException {
        //第一种:通过Class.forName获取
        Class<?> aClass = Class.forName("com.wqg.fanshe.demo01.Student");
        System.out.println(aClass);
        //第二种:通过类名获取
        Class<Student> aClass1 = Student.class;
        System.out.println(aClass1);
        //第三种:通过对象获取
        Student student = new Student();
        Class<? extends Student> aClass2 = student.getClass();
        System.out.println(aClass2);
        
       //aClass和aClass1和aClass2地址是一致的
       System.out.println(aClass==aClass1);//true
       System.out.println(aClass1==aClass2);//true
       //从结果得出:同一个类的字节码只会被加载jvm内存一次
    }
}
class Student{
}

3.通过反射类获取相应的类对象

反射对象.newInstance();         ( 根据反射类找到该类的实例对象)

public class Test02 {
    public static void main(String[] args) throws Exception {
        //得到反射类对象
        Class<?> aClass = Class.forName("com.wqg.fanshe.demo02.Student");
        //通过反射类获取相应的类对象 //默认调用无参构造函数
        Student o = (Student) aClass.newInstance();
        System.out.println(o);
    }
}
class Student{
}

4.通过反射获取属性类对象

Field[ ] getDeclaredFields(): 获取本类中所有的属性对象

Field getDeclaredField(String name) : 获取本类中指定的属性对象

Field[ ] getFields() :获取本类以及父类中public属性对象

Field getField(String name) : 获取本类以及父类中指定的public属性对象

public class Test03 {
    public static void main(String[] args) throws Exception {
        Class<Student> aClass = Student.class;
        System.out.println("====获取本类中的所有属性===");
        Field[] fields = aClass.getDeclaredFields();
        for (Field field :fields){
            System.out.println(field);
        }
        System.out.println("====获取本类以及父类中的public属性对象====");
        Field[] fields1 = aClass.getFields();
        for (Field field2 :fields1){
            System.out.println(field2);
        }
        System.out.println("===获取本类中指定的属性===");
        Field sex = aClass.getDeclaredField("sex");  //只能拿到本类,不能拿父类
        System.out.println(sex);
        System.out.println("===获取本类以及父类中指定的public属性对象===");
        Field a = aClass.getField("height");
        System.out.println(a);
    }
}
class People{ //父类
    public String height;//身高
    public String weight; //体重
}
class Student extends People{//子类
    public String name;//公共属性
    private int age;  //私有属性
    String address;  //默认属性
    protected  String sex;//受保护的属性
}

5.通过Field操作类中属性

.setAccessible(true) //设置私有访问权限

set(o,"刘德华")

public class Test04 {
    public static void main(String[] args) throws Exception {
        //得到反射类对象
        Class<?> aClass = Class.forName("fanshe.demo04.Student");
        //通过反射类获取相应的类对象
        Object o = aClass.newInstance();
        System.out.println(o);

        //为类中对象赋值
        Field nameField = aClass.getDeclaredField("name");
        int modifiers = nameField.getModifiers();//拿到修饰符  //private=2  public=1 default=0  protected=4
        System.out.println(modifiers+"==============拿到修饰符=================");
        nameField.set(o, "刘德华"); //两个参:(Object obj:对象, Object value:值)
        System.out.println(o+"======为类中对象赋值=====");


        Field ageField = aClass.getDeclaredField("age");
        //设置私有访问权限
        ageField.setAccessible(true);
        ageField.set(o, 20); //两个参:(Object obj:对象, Object value:值)
        System.out.println(o);

        //取值
        Object o1 = nameField.get(o);//通过属性对象获取属性值
        System.out.println(o1);

        Annotation[] annotations = nameField.getAnnotations(); //拿到name属性上所有的注解
        System.out.println(Arrays.asList(annotations));
        //nameField.getAnnotation();//获取指定的注解  返回一个对象
    }
}

@Retention(RetentionPolicy.RUNTIME) //注解默认字节码时有效  改成运行时有效
@interface My {
    String name();
}

class Student {

    @My(name = "张学友")
    public String name;//公共属性
    private int age;  //私有属性
    String address;  //默认属性
    protected String sex;//受保护的属性

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                ", sex='" + sex + '\'' +
                '}';
    }
}

6.通过反射获取方法类对象

getMethods():   拿到本类及父类所有public的方法

getMethod(方法名  , 参数类型)   

getDeclaredMethods()  得到本类中所有方法

getDeclaredMethod(方法名  , 参数类型) 

//例:
Method show = sonClass.getDeclaredMethod("show",int.class,String.class);
public class Test04 {
    public static void main(String[] args) throws Exception {
        //得到反射类对象
        Class<Son> sonClass = Son.class;
        //通过反射类获取相应的类对象
        Son son = sonClass.newInstance();
        //通过反射获取方法类对象
        Method show = sonClass.getDeclaredMethod("show",int.class,String.class);
        show.setAccessible(true);
        Object o = show.invoke(son, 20, "张三");//invoke执行该方法
        System.out.println(o);//拿到返回值

    }
}

class Son{
    private String name;
    public int age;

    private String show(int a,String b){
        System.out.println("======show方法======"+a+"岁;名字:"+b);
        return "今天晴天";
    }
    @Override
    public String toString() {
        return "Son{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

6.1.Method类中常见的方法

Object  invoke(Object  o , Object...  values)        invoke方法的回调

//例
  Object o = show.invoke(son, 20, "张三");//invoke执行该方法
        System.out.println(o);//拿到返回值

7.通过反射获取构造方法对象

getConstructor(类<?>... parameterTypes):获取本类以及父类中指定的public构造方法

getConstructors():获取本类以及父类中所有public构造方法对象

getDeclaredConstructor(类<?>... parameterTypes)

getDeclaredConstructors()      

...  代表可变参

 

public class Test04 {
    public static void main(String[] args) throws Exception {
        //得到反射类对象
        Class<?> aClass = Class.forName("fanshe.demo06.Son");
        Constructor<?> constructor = aClass.getConstructor();//getConstructor获取无参构造函数
        Object o = constructor.newInstance(); //通过构造函数获取到相应的实例对象
        System.out.println(o);

        Constructor<?> constructor1 = aClass.getConstructor(String.class, int.class);//获取有参构造
        Object o1 = constructor1.newInstance("刘德华", 18);//属性赋值
        System.out.println(o1);

    }
}

class Son{
    private String name;
    public int age;

    private String show(int a,String b){
        System.out.println("======show方法======"+a+"岁;名字:"+b);
        return "今天晴天";
    }

    public Son(String name){this.name=name;}
    public Son(){}
    public Son(String name,int age){
        this.name=name;
        this.age=age;
    }
    @Override
    public String toString() {
        return "Son{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

8.通过反射获取类上的注解

getAnnotations():获取类上的所有注解 

getAnnotation(Class):获取类上指定的注解

public class Test07 {
    public static void main(String[] args) {
        Class<People> aClass = People.class;//获取反射类
        Annotation[] annotations = aClass.getAnnotations();//获取类上的所有注解
        System.out.println(Arrays.toString(annotations));

    }
}

@My
@My2
class People{

}
@Retention(RetentionPolicy.RUNTIME) //运行时有效
@interface My{

}

@Retention(RetentionPolicy.RUNTIME) //运行时有效
@interface My2{

}

8.1.通过注解对象操作注解中相关的属性

getAnnotation(Class):获取类上指定的注解

public class Test07 {
    public static void main(String[] args) {
        Class<People> aClass = People.class;//获取反射类
        My annotation = aClass.getAnnotation(My.class); //获取类上指定的注解
        int age = annotation.age();
        System.out.println(age);
    }
}

@My(name = "刘德华",age = 20)
@My2
class People{

}
@Retention(RetentionPolicy.RUNTIME) //运行时有效
@interface My{
    String name() default "张三" ;
    int age();

}

@Retention(RetentionPolicy.RUNTIME) //运行时有效
@interface My2{

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值