泛型和注解

1.什么是泛型

其实我们再使用集合时就用过泛型List<T> 创建一个List对象List<Student> list=new ArrayList();

其中<T>它就是泛型。

所谓的泛型就是在定义时,不为类中的属性和方法指定数据类型,而是在类创建的时候指定响应的数据类型

2.为什么使用泛型

        我们举一个列子,当我再类要求有String类型 int类型,那么我们应该如何定义类型呢?--Object类型

实体类

package practice;

/**
 * TODO
 *
 * @author lenovo
 * @version 1.0
 * @since 2022-07-13  20:23:38
 */
public class Practice {
    //属性
    private Object a;
    private Object b;
    public void show(){
        System.out.println(a+";"+b);
    }
    //无参
    public Practice() {
    }
    //有参
    public Practice(Object a, Object b) {
        this.a = a;
        this.b = b;
    }

    public Object getA() {
        return a;
    }

    public void setA(Object a) {
        this.a = a;
    }

    public Object getB() {
        return b;
    }

    public void setB(Object b) {
        this.b = b;
    }
}

测试类

package practice;

/**
 * TODO
 *
 * @author lenovo
 * @version 1.0
 * @since 2022-07-13  20:28:18
 */
public class PracticeTest {
    public static void main(String[] args) {
        Practice p1=new Practice("上海","北京");
        p1.show();
        Practice p2=new Practice(1,2);
        p2.show();
    }
}

如果有一个是String类型,一个是int 类型,它违背了我们设计的要求,这就是我们提到的数据类型安全问题。如何解决数据类型安全问题? ---使用泛型来解决

实体类

package practice;

/**
 * TODO
 *
 * @author lenovo
 * @version 1.0
 * @since 2022-07-13  20:23:38
 */
public class Practice1<T>{
   private T name;
   private T age;

   public void show(){
       System.out.println(name+";"+age);
   }
    public Practice1(T name, T age) {
        this.name = name;
        this.age = age;
    }

    public T getName() {
        return name;
    }

    public void setName(T name) {
        this.name = name;
    }

    public T getAge() {
        return age;
    }

    public void setAge(T age) {
        this.age = age;
    }
}

测试类

package practice;

/**
 * TODO
 *
 * @author lenovo
 * @version 1.0
 * @since 2022-07-13  20:28:18
 */
public class PracticeTest1 {
    public static void main(String[] args) {
     Practice1<String> p1=new Practice1<String>("张三","12");
     p1.show();
    }
}

注意: 上面的泛型类型必须都是引用类型。不能是基本类型。使用泛型就保证了数据类型安全问题

3.如何定义泛型

泛型可以定义在类上,接口上,方法上。 泛型类,泛型接口以及泛型方法。

扫描二维码关注公众号,回复: 14462265 查看本文章

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

public class 类名<泛型标志,泛型标志....>{

          可以有多个泛型标志,泛型标志与泛型标志之间用逗号隔开
}

package practice;

/**
 * TODO
 *
 * @author lenovo
 * @version 1.0
 * @since 2022-07-13  20:23:38
 */
public class Practice2<T>{
    //T任意类型
  private T name;

  public void show(){
      System.out.println(name);

  }
  public Practice2(T name) {
        this.name = name;
    }

    public T getName() {
        return name;
    }

    public void setName(T name) {
        this.name = name;
    }
}
package practice;

/**
 * TODO
 *
 * @author lenovo
 * @version 1.0
 * @since 2022-07-13  20:28:18
 */
public class PracticeTest2 {
    public static void main(String[] args) {
     Practice2<String> p1=new Practice2<>("张三");
     p1.show();
     Practice2<Integer> p2=new Practice2<>(2);
     p2.show();
     //如果没有指定泛型的数据类型,那么默认是Object类型
     Practice2 p3=new Practice2(3);
     p3.show();
    }
}

4.通配符

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

package practice;

/**
 * TODO
 *
 * @author lenovo
 * @version 1.0
 * @since 2022-07-13  20:23:38
 */
public class Practice3<T>{
    public static void main(String[] args) {
        //如果是泛型,不但要求数据类型相同,还要求泛型类型相同
        Practice3<String> practice3=new Practice3<>();
        practice3.setName("李四");
        practice3.show();

        Practice3 <Integer> p3=new Practice3<>();
        p3.setName(2);
        p3.show();
    }
//? 代表通配符--泛型类型是任意类型
    public static void fun(Practice3<?> practice3){
        practice3.show();
    }
    //T任意类型
    private T name;
    public void show(){
        System.out.println(name);
    }

    public Practice3() {
    }

    public Practice3(T name) {
        this.name = name;
    }

    public T getName() {
        return name;
    }

    public void setName(T name) {
        this.name = name;
    }


}

5.受限泛型

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

[设置上限]
声明对象: 类名称<? extends 类> 对象名称;
定义类:  [访问权限] 类名称<泛型标识 extends 类>{}

[设置下限]
声明对象: 类名称<? super 类> 对象名称;
定义类:  [访问权限] 类名称<泛型标识 super 类>{}

1.范围上限

package practice;

/**
 * TODO
 *
 * @author lenovo
 * @version 1.0
 * @since 2022-07-13  20:23:38
 */
public class Practice4<T>{
    public static void main(String[] args) {
        Practice4<Integer> p4=new Practice4<>();
        p4.setName(3);
        p4.show();
    }
//? 代表通配符--泛型类型是任意类型  上限--Number类型或者Number的子类
    public static void fun(Practice4<? extends Number> practice3){
        practice3.show();
    }
    //T任意类型
    private T name;
    public void show(){
        System.out.println(name);
    }

    public Practice4() {
    }

    public Practice4(T name) {
        this.name = name;
    }

    public T getName() {
        return name;
    }

    public void setName(T name) {
        this.name = name;
    }


}

2.范围下限

       Practice4<Number> practice4=new Practice4<>();
        practice4.setName(24.4);
       f(practice4);
    }
    //范围下限---Number的父类或者number
    public static void f(Practice4<? super Number> practice4){
        practice4.show();
    }

6.泛型接口

jdk1.5以后,泛型也可以定义在接口上了,定义接口的泛型和定义泛型类语法相似。

语法:

public interface 接口名<泛型标志,泛型标志....>{
   //静态常量
   //抽象方法。
}

//泛型接口
public interface Generic<T> {
    // public static final String NAME=""; //常量的命名必须全部大写。--必须要有值
    //抽象方法
   T eat();
   //jdk1.8之后新增的  default--默认 static--静止
    default void fun(){}
    static void fun2(){}
}
package guan;

/**
 * TODO
 *
 * @author lenovo
 * @version 1.0
 * @since 2022-07-13  19:24:51
 * 实现Generic泛型接口
 */
//在实现接口的时候,确定泛型
public class Person implements Generic<String>{

    @Override
    public String eat() {
        return "炸鸡可乐真实绝配";
    }

    //子类实现接口时,子类泛型和父类的泛型相同
    class Music<T> implements Generic<T>{
        @Override
        public T eat() {
            return null;
        }
    }
}

7.泛型方法

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

【泛型方法的简单定义】

[访问权限] <泛型标识> 泛型标识 方法名称(泛型标识 参数名称)

package practice;

/**
 * TODO
 *
 * @author lenovo
 * @version 1.0
 * @since 2022-07-13  20:23:38
 */
public class Practice5<T>{
    public static void main(String[] args) {
        //fun里面是什么类型,返回的就是什么类型
        Integer fun = student.fun(2000);
    }
    
}
class student{
    //泛型方法  static--静态方法,会随着类的加载而被加载到JVM内存中
    public static <T> T fun(T t){
        return t;
    }
}

9.注解

注释: java不会编译注释的内容,注释给程序员看的。

注解: 它是程序看,当程序看到这个注解时,就应该解析它。

1.注解的分类

        1. 预定义注解--预定义注解就是JDK自带的一些注解,该注解被JVM而解析。
        2. 自定义注解
        3. 元注解

注意: 使用注解和不使用注解没有区别?

注解本身没有任何意义,它只有被解析了,才会赋予真正的意义。

我们后会使用反射来对象注解进行解析。

像:@Override 它被JVM解析,从而使其具有相应的意义。

​ @Controller @RequestMapping 它被Spring框架解析,所以具有相应的意义。

        1.预定义注解

                1. @Override: 重写得注解。符合重写得规则。

package practice;

/**
 * TODO
 *
 * @author lenovo
 * @version 1.0
 * @since 2022-07-13  20:23:38
 */
public class Practice6 implements a{
    //重写方法--该方法必须与父类的中的方法名相同,参数相同,返回类型相同,修饰符不能小于
    //父类方法的修饰符,抛出异常不能大于父类
    @Override
    public Object my() {
        return null;
    }
}


                2. @Deprecated: 表示已过时。

   }
    //方法过时--replace by show ->show2() 该方法被show2代替
    @Deprecated
    public void show(){
        
    }
}


                3. @SuppressWarnings: 表示压制警告。
                4. @FunctionInterface: 表示函数式接口。表示该接口中有且仅有一个抽象方法。

        2.自定义注解

            语法:

@interface 注解名{
     数据类型 属性名() default 默认值;
数据类型: 基本类型,字符串类型,枚举类型【常量】,注解类型,数组类型【必须是上面这些类型的数组】
}

        3.元注解

定义到注解上的注解成为元注解

1. @Target(value=可以取下面这些内容): 作用限制注解使用得位置。
    /** 表示可以作用在类,接口,枚举 */
    TYPE,

    /** 属性 */
    FIELD,

    /** 普通方法上 */
    METHOD,

    /** 方法参数 */
    PARAMETER,

    /** 构造方法上 */
    CONSTRUCTOR,

    /** 局部变量 */
    LOCAL_VARIABLE

2. @Retention(value=)  注解什么时候生效。默认时源码 java经历了那些阶段。
      源码阶段-->字节码阶段--->运行阶段
      /**
     * 源码时生效
     */
    SOURCE,

    /**
     * 字节码时生效
     */
    CLASS,

    /**
     * 运行时生效。
     * 在JVM内存中还有该注解。
     都会被设置为运行时有效
     */
    RUNTIME
    
3. @Documented 当生产API文档时该注解还存在。 

4. @Inherited 是否运行被子类继承。

猜你喜欢

转载自blog.csdn.net/ne_123456/article/details/125771865