Java高级 泛型和注解

一、泛型

1、什么是泛型?

List<T> list = new ArrayList<>();

 这里我们之前在使用集合时,就已经用过泛型,其中的  “<T>” 就是泛型。

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

2、为什么使用泛型?

我们举一个例子来说。

现在要求定义一个Point类,该类中要有属性:坐标x,坐标y。

要求1: x和y的值可以都是整数类型

要求2: x和y的值可以都是小数类型。

要求3:x和y的值可以都是字符串类型。

在不考虑泛型这种方法,我们之前想要实现上面的要求,类该如何定义?

我们可以将属性x和属性y的类型设置为Object,这样就可以实现上面的要求。

Point类代码:

package test.demo01;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/13 20:00
 **/
public class Point {
    private Object x;
    private Object y;
    
    //无参构造
    public Point() {
    }

    //有参构造
    public Point(Object x, Object y) {
        this.x = x;
        this.y = y;
    }

    //自定义一个show方法,方便演示
    public void show(){
        System.out.println("x坐标:"+x+";y坐标:"+y);
    }
    
    //get set方法
    public Object getX() {
        return x;
    }

    public void setX(Object x) {
        this.x = x;
    }

    public Object getY() {
        return y;
    }

    public void setY(Object y) {
        this.y = y;
    }
}

要求实现测试代码:

package test.demo01;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/13 20:02
 **/
public class TestPoint {
    public static void main(String[] args) {
        Point p1=new Point(10,20);//坐标为整数,实现要求1
        p1.show();

        Point p2=new Point(10.5,20.5);//坐标为小数,实现要求2
        p2.show();

        Point p3=new Point("E105°","N100°");//坐标为字符串,实现要求3
        p3.show();
    }
}

控制台输出:

x坐标:10;y坐标:20
x坐标:10.5;y坐标:20.5
x坐标:E105°;y坐标:N100°

 但是我们思考一下,这种情况虽然满足了我们提出的三个要求,但是这种方式会出现要求外的情况,比如x属性我传一个字符串,y属性我传一个Double,这显然违背了我们的预期。这种情况在java中可以作为一种数据类型安全问题。如果想解决这种问题,就需要用到我们的泛型。

使用泛型后的Point类:

package test.demo01;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/13 20:00
 **/
public class Point<T> {
    private T x;
    private T y;

    public Point() {
    }

    public Point(T x, T y) {
        this.x = x;
        this.y = y;
    }

    //自定义一个show方法,方便演示
    public void show(){
        System.out.println("x坐标:"+x+";y坐标:"+y);
    }

    public T getX() {
        return x;
    }

    public void setX(T x) {
        this.x = x;
    }

    public T getY() {
        return y;
    }

    public void setY(T y) {
        this.y = y;
    }
}

将Point类改写成这样后,就避免了出现数据类型安全问题。这时我们规定好泛型后,再想一个传字符串类型数据,一个传Double类型数据就不可能实现了。

 其实用泛型,如果想的话,也可以实现一个传字符串,一个传Doule这种形式,这时需要我们在定义类时,规定两个泛型<T,E>。具体的定义泛型我们在后面详细讲解。

注意:上面的泛型类型必须都是引用类型。不能是基本类型。

4、泛型的定义

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

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

注意:

  • 标识可以任意起名,在创建对象时,必须为每个泛型指定数据类型。
  • 在类声明或实例化时,如果没有指定泛型的类型,那么默认类型为Object.
  • 如果不声明类型,想使用真正的类型接收,则必须进行强转。

格式:

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

     //类成员
}

package test.demo01;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/13 20:02
 **/
public class TestPoint {
    public static void main(String[] args) {
        Point<Integer> p1=new Point<>(10,20);
        p1.show();

        Point<Double> p2=new Point<>(10.5,20.5);
        p2.show();

        Point<String> p3=new Point<>("E105°","N100°");
        p3.show();
        
        //不规定泛型,默认为Object
        Point point = new Point(10,20);
        //想要类型为Integer,则必须要强转
        Integer x = (Integer) point.getX();

    }
}

5、通配符

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

例子:我们在测试类中定义一个方法---doshow(Point<?> point),让该方法的参数为Point

package test.demo01;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/13 20:02
 **/
public class TestPoint {
    public static void main(String[] args) {
        Point<Integer> point = new Point<>(10,20);
        doshow(point);
    }

    public static void doshow(Point<?> point){
        point.show();
    }
}

6、受限泛型

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

语法:

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

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

例子:设置fun方法引用point对象中的show方法,且泛型上限为Number;设置look方法引用point对象 的show方法,且泛型下限为Number;

7、泛型接口

上面那些例子都是使用泛型类。而在jdk1.5以后,泛型也可以定义在接口上了,定义接口的泛型和定义泛型类语法相似。

语法:

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

 类实现泛型接口

USB泛型接口:

package test.demo02;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/13 20:47
 **/
public interface USB<T> {
    //常量
    String NAME="";
    //抽象方法
    T show();
}

子类实现接口时,确定泛型类型

package test.demo02;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/13 20:49
 **/
public class Mouse implements USB<String>{
    @Override
    public String show() {
        return "show mouse";
    }
}

子类实现接口,子类也实现和父类相同的泛型

package test.demo02;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/13 20:52
 **/
public class KeyBoard<T> implements USB<T> {
    @Override
    public T show() {
        return null;
    }
}

测试两个子类:

package test.demo02;



/**
 * @作者:刘壬杉
 * @创建时间 2022/7/13 20:54
 **/
public class Test02 {
    public static void main(String[] args) {
        //子类在实现接口时,确定泛型类型
        Mouse mouse = new Mouse();
        mouse.show();

        //子类也实现泛型和父类名相同的泛型
        KeyBoard<Integer> keyBoard = new KeyBoard<>();
        keyBoard.show();
    }
}

8、泛型方法

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

泛型方法的定义:

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

package test.demo03;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/13 20:57
 **/
public class Point {
    public <T> T fun(T t){
        return t;
    }
}

 测试类代码:

package test.demo03;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/13 20:59
 **/
public class Test03 {
    public static void main(String[] args) {
        Point point = new Point();
        String str = point.fun("fanxingfangfa");
        System.out.println(str);

        Integer fun = point.fun(11);
        System.out.println(fun);

        Double fun1 = point.fun(22.5);
        System.out.println(fun1);
    }
}

二、注解

注解就是给程序看的东西,当程序看到这个注解时,就会解析这个注解。

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

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

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

 1、预定义注解

预定义注解就是JDK自带的一些注解,该注解被JVM而解析。

常用的预定义注解:

1. @Override: 重写得注解。符合重写得规则。
2. @Deprecated: 表示已过时。
3. @SuppressWarnings: 表示压制警告。
4. @FunctionInterface: 表示函数式接口。表示该接口中有且仅有一个抽象方法。

2、自定义注解(初级篇)

语法:

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

 使用自定义注解:

类 方法  属性 加@注解名

 例子:注意,该例子中的自定义注解没有任何意义,因为他没有被解析,只有解析过后才会被赋予真正的意义。解析方法需要用到我们的反射。这个后面我们再讲

package demo03;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/13 19:32
 **/
public class Test03 {
    public static void main(String[] args) {
        Fun fun = new Fun();
        fun.setA(15);
        fun.dofun();
    }
}


//自定义注解
@interface lrs{
    //注解属性
}

//使用注解
@lrs
class Fun{
    @lrs
    private Integer a;

    @lrs
    public void dofun(){
        System.out.println(a);
    }

    public Integer getA() {
        return a;
    }

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

3、元注解

元注解就是定义在注解上的注解称为元注解。 我们只需要知道下面这四个。

 @Target(value=可以取下面这些内容): 作用限制注解使用得位置。

                ElementType.TYPE :表示注解可以作用在类,接口,枚举上

                ElementType.FIELD :表示注解可以作用在属性上

                ElementType.METHOD:表示注解可以作用在普通方法上

                ElementType.PARAMETER:表示注解可以作用在方法参数上

                ElementType.CONSTRUCTOR:表示注解可以作用在构造方法上

                ElementType.LOCAL_VARIABLE:表示注解可以作用在局部变量上

 @Retention:  注解什么时候生效。默认时源码 java经历了那些阶段。

                                 源码阶段-->字节码阶段--->运行阶段

                RetentionPolicy.SOURCE:源码时生效

                RetentionPolicy.CLASS:字节码时生效

                RetentionPolicy.RUNTIME:运行时生效

范围最大的是RUNTIME,他会在源码阶段,字节码阶段,运行阶段都有该注解

 @Documented 当生产API文档时该注解还存在。

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

4.自定义注解(高级篇)

语法:

@interface 注解名{
     数据类型 属性名() default 默认值;
}

 注意:这里的数据类型必须为:基本类型,字符串类型,枚举类型【常量】,注解类型,数组类型【必须是上面这些类型的数组】

例子:

package question4;

/**
 * @作者:刘壬杉
 * @创建时间 2022/7/13 19:40
 **/

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//只能在类上使用
@Target(value= ElementType.TYPE)
//在运行时有效
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationByCustom {
    String[] name () default "dimooo时光漫游系列";
    String[] value();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值