首页 > 编程语言 >Java base(1):注解、泛型、通配符、重载、重写

Java base(1):注解、泛型、通配符、重载、重写

时间:2024-06-01 17:28:26浏览次数:16  
标签:Java ArrayList 通配符 接口 类型 base 泛型 public

注解:

用于在代码中插入元数据,不会直接影响程序的执行,但可以被编译器、开发工具或运行时环境用来处理特定任务,如编译时检查、生成额外的代码、进行框架级配置等。

  1. 预定义注解:java给的,例如:@Override:用于标记一个方法是重写父类的方法。
  2. 自定义注解
  3. 元注解:注解其他注解的注解。

元数据:关于数据的数据,提供了描述或解释其他数据的信息,包括但不限于数据库、文档管理、编译器、网络协议和编程语言中的注解等。在Java中,注解是元数据的一种形式。它们为代码提供附加信息,但这些信息不直接影响代码的执行

元数据的作用:

  1. 描述数据:提供关于数据的详细信息,例如类型、格式、长度等。
  2. 数据管理:帮助组织和管理数据,便于查找和使用。
  3. 提高可读性:提供额外的信息,使代码更加清晰和易于理解。
  4. 自动化处理:支持自动化工具和框架进行数据处理,例如代码生成、依赖注入、数据验证等。

元数据在其他领域的应用:

  1. 数据库:数据库中的元数据描述了表、列、数据类型、索引等信息。
  2. 文档管理:文档元数据可以包括标题、作者、创建日期、关键词等。
  3. 网络协议:网络协议中的元数据可能描述了数据包的长度、来源、目的地等信息。

参考:Java 中的泛型(两万字超全详解)_java 泛型-CSDN博客

泛型:

参数化类型,即允许类、接口和方法定义中使用类型参数,这些类型参数在实际使用时会被具体的类型实例化。

三种使用形式:

1.泛型类:类型参数用于类的定义中,则该类被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口。最典型的就是各种容器类,如:List、Set、Map等。

//基本语法:
class 类名称 <泛型标识> {
  private 泛型标识 /*(成员变量类型)*/ 变量名; 
  .....

  }
}


//常见的泛型标识:
  T :代表一般的任何类。
  E :代表 Element 元素的意思,或者 Exception 异常的意思。
  K :代表 Key 的意思。
  V :代表 Value 的意思,通常与 K 一起配合使用。
  S :代表 Subtype 的意思。

//举例:
public class Generic<T> { 
    // key 这个成员变量的数据类型为 T, T 的类型由外部传入  
    private T key;

	// 泛型构造方法形参 key 的类型也为 T,T 的类型由外部传入
    public Generic(T key) { 
        this.key = key;
    }
    
	// 泛型方法 getKey 的返回值类型为 T,T 的类型由外部指定
    public T getKey(){ 
        return key;
    }
}

从上述例子可得,在泛型类中,类型参数定义的位置有三处:

  1.非静态的成员属性类型
  2.非静态方法的形参类型(包括非静态成员方法和构造器)
  3.非静态的成员方法的返回值类型
 

泛型类的使用:在创建泛型类的对象时,必须指定类型参数 T 的具体数据类型,即尖括号 <> 中传入的什么数据类型,T 便会被替换成对应的类型。如果 <> 中什么都不传入,则默认是 < Object >。

假设有如下泛型类:

public class Generic<T> { 
 
    private T key;

    public Generic(T key) { 
        this.key = key;
    }

    public T getKey(){ 
        return key;
    }
}

当创建一个 Generic< T > 类对象时,会向尖括号 <> 中传入具体的数据类型。

@ Test
public void test() {
	Generic<String> generic = new Generic<>();// 传入 String 类型
	
	// <> 中什么都不传入,等价于 Generic<Object> generic = new Generic<>();
	Generic generic = new Generic();
}

2.泛型接口:

//基本语法
public interface 接口名<类型参数> {
    ...
}


//举例
public interface Inter<T> {
    public abstract void show(T t) ;
}

泛型接口中的类型参数,在该接口被继承或者被实现时确定。

(1)定义一个泛型接口如下:

  • 注意:在泛型接口中,静态成员也不能使用泛型接口定义的类型参数。
interface IUsb<U, R> {

    int n = 10;
    U name;// 报错! 接口中的属性默认是静态的,因此不能使用类型参数声明

    R get(U u);// 普通方法中,可以使用类型参数

    void hi(R r);// 抽象方法中,可以使用类型参数

    // 在jdk8 中,可以在接口中使用默认方法, 默认方法可以使用泛型接口的类型参数
    default R method(U u) {
        return null;
    }
}

(2)定义一个接口 IA 继承了 泛型接口 IUsb,在 接口 IA 定义时必须确定泛型接口 IUsb 中的类型参数。

// 在继承泛型接口时,必须确定泛型接口的类型参数
interface IA extends IUsb<String, Double> {
	...
}

// 当去实现 IA 接口时,因为 IA 在继承 IUsu 接口时,指定了类型参数 U 为 String,R 为 Double
// 所以在实现 IUsb 接口的方法时,使用 String 替换 U,用 Double 替换 R
class AA implements IA {
    @Override
    public Double get(String s) {
        return null;
    }
    @Override
    public void hi(Double d) {
		...
    }
}

(3)定义一个类 BB 实现了 泛型接口 IUsb,在 类 BB 定义时需要确定泛型接口 IUsb 中的类型参数。

// 实现接口时,需要指定泛型接口的类型参数
// 给 U 指定 Integer, 给 R 指定了 Float
// 所以,当我们实现 IUsb 方法时,会使用 Integer 替换 U, 使用 Float 替换 R
class BB implements IUsb<Integer, Float> {
    @Override
    public Float get(Integer integer) {
        return null;
    }
    @Override
    public void hi(Float afloat) {
		...
    }
}

(4)定义一个类 CC 实现了 泛型接口 IUsb 时,若是没有确定泛型接口 IUsb 中的类型参数,则默认为 Object。

// 实现泛型接口时没有确定类型参数,则默认为 Object
// 建议直接写成 IUsb<Object, Object>
class CC implements IUsb {//等价 class CC implements IUsb<Object, Object> 
    @Override
    public Object get(Object o) {
        return null;
    }
    @Override
    public void hi(Object o) {
    	...
    }
}

(5)定义一个类 DD 实现了 泛型接口 IUsb 时,若是没有确定泛型接口 IUsb 中的类型参数,也可以将 DD 类也定义为泛型类,其声明的类型参数必须要和接口 IUsb 中的类型参数相同。

// DD 类定义为 泛型类,则不需要确定 接口的类型参数
// 但 DD 类定义的类型参数要和接口中类型参数的一致
class DD<U, R> implements IUsb<U, R> { 
	...
}

3.泛型方法:-------------------------

通配符:

泛型能够处理某一类型范围内的类型参数,比如某个泛型类和它的子类,为此 Java 引入了泛型通配符这个概念。

泛型通配符有 3 种形式:

  1. <?> :被称作无限定的通配符。
  2. <? extends T> :被称作有上界的通配符。
  3. <? super T> :被称作有下界的通配符。

在引入泛型通配符之后,我们便得到了一个在逻辑上可以表示为某一类型参数范围的父类引用类型。举例来说,泛型通配符可以表示 Pair< Integer > 和 Pair< Number > 两者的父类引用类型

1.上界通配符

<? extends T> 的定义
上界通配符 <? extends T>:T 代表了类型参数的上界,<? extends T>表示类型参数的范围是 T 和 T 的子类。需要注意的是: <? extends T> 也是一个数据类型实参,它和 Number、String、Integer 一样都是一种实际的数据类型。

上界通配符表示类型是 TT 的子类。它限制了泛型类型的上限,使得泛型类型必须是指定类型的子类型。常用于只需要读取数据的场景。

作用
  • 读取数据:确保读取的数据类型至少是 T,保证类型安全。
  • 协变性:使得泛型能够处理 T 及其子类的集合,增加了泛型方法的灵活性。

public class GenericType {
    public static void main(String[] args) {  
		ArrayList<Number> list01 = new ArrayList<Integer>();// 编译错误

		ArrayList<? extends Number> list02 = new ArrayList<Integer>();// 编译正确
    }  
}

用法:

public class Test {
    public static void main(String[] args) {
    	// 创建一个 ArrayList<Integer> 集合
        ArrayList<Integer> integerList = new ArrayList<>();
        integerList.add(1);
        integerList.add(2);
        // 将 ArrayList<Integer> 传入 printIntVal() 方法
        printIntVal(integerList);
		
		// 创建一个 ArrayList<Float> 集合
        ArrayList<Float> floatList = new ArrayList<>();
        floatList.add((float) 1.0);
        floatList.add((float) 2.0);
        // 将 ArrayList<Float> 传入 printIntVal() 方法
        printIntVal(floatList);
    }
    
    public static void printIntVal(ArrayList<? extends Number> list) {
 		// 遍历传入的集合,并输出集合中的元素       
        for (Number number : list) {
            System.out.print(number.intValue() + " ");
        }
        System.out.println();
    }
}

2.下界通配符:

下界通配符 <? super T>:T 代表了类型参数的下界,<? super T>表示类型参数的范围是 T 和 T 的超类,直至 Object。需要注意的是: <? super T> 也是一个数据类型实参,它和 Number、String、Integer 一样都是一种实际的数据类型。

ArrayList<? super Integer> 在逻辑上表示为 Integer 类以及 Integer 类的所有父类,它可以代表 ArrayList< Integer>、ArrayList< Number >、 ArrayList< Object >中的某一个集合,但实质上它们之间没有继承关系。

下界通配符表示类型是 TT 的超类。它限制了泛型类型的下限,使得泛型类型必须是指定类型的超类型。常用于需要向集合中添加数据的场景。

  • 写入数据:确保向集合中添加的数据类型至少是 T,保证类型安全。
  • 逆变性:使得泛型能够处理 T 及其超类的集合,增加了泛型方法的灵活性。

public class GenericType {
    public static void main(String[] args) {  
		ArrayList<Integer> list01 = new ArrayList<Number>();// 编译错误

		ArrayList<? super Integer> list02 = new ArrayList<Number>();// 编译正确
    }  
}

用法:

public class Test {
	public static void main(String[] args) {
		// 创建一个 ArrayList<? super Number> 集合
		ArrayList<Number> list = new ArrayList(); 
		// 往集合中添加 Number 类及其子类对象
		list.add(new Integer(1));
		list.add(new Float(1.1));
		// 调用 fillNumList() 方法,传入 ArrayList<Number> 集合
		fillNumList(list);
		System.out.println(list);
	}
	
	public static void fillNumList(ArrayList<? super Number> list) {
		list.add(new Integer(0));
		list.add(new Float(1.0));
	}
}

3.无限定通配符 <?>

? 代表了任何一种数据类型,能代表任何一种数据类型的只有 null。需要注意的是: <?> 也是一个数据类型实参,它和 Number、String、Integer 一样都是一种实际的数据类型。

(1)ArrayList<?> 在逻辑上表示为所有数据类型的父类,它可以代表 ArrayList< Integer>、ArrayList< Number >、ArrayList< Object >中的某一个集合,但实质上它们之间没有继承关系。

public class GenericType {
	public static void main(String[] args) {
        ArrayList<Integer> list01 = new ArrayList<>(123, 456);
        ArrayList<?> list02 = list01; // 安全地向上转型
    }
}

(2)ArrayList<?> 既没有上界也没有下界,因此,它可以代表所有数据类型的某一个集合,但我们不能指定 ArrayList<?> 的数据类型。

public class GenericType {
	public static void main(String[] args) {
        ArrayList<?> list = new ArrayList<>();
        list.add(null);// 编译正确
        Object obj = list.get(0);// 编译正确

		list.add(new Integer(1));// 编译错误
		Integer num = list.get(0);// 编译错误
    }
}

(3)大多数情况下,可以用类型参数 < T > 代替 <?> 通配符。

上界通配符<?extends T> 和下界通配符<? super T>的区别

  1. 读取与写入

    • 上界通配符 (? extends T):主要用于读取数据,不能写入数据(除了 null)。
    • 下界通配符 (? super T):主要用于写入数据,读取数据时只能读取为 Object 类型。

<? extends T> 允许调用读方法T get()获取 T 的引用,但不允许调用写方法 set(T)传入 T 的引用(传入 null 除外)。
<? super T> 允许调用写方法set(T)传入 T 的引用,但不允许调用读方法 T get()获取 T 的引用(获取 Object 除外)。

  1. 适用场景

    • 上界通配符:适用于对集合进行只读操作的场景,如计算总和、遍历等。编译器将只允许读操作,不允许写操作。即只可以取值,不可以设值。
    • 下界通配符:适用于对集合进行写操作的场景,如添加元素。编译器将只允许写操作,不允许读操作。即只可以设值(比如 set 操作),不可以取值(比如 get 操作)。
  2. 协变与逆变

    • 上界通配符:协变性,允许泛型处理 T 及其子类。
    • 下界通配符:逆变性,允许泛型处理 T 及其超类。
  3. 类型安全

    • 上界通配符:在读取时保证类型安全,因为只能读取 TT 的子类。
    • 下界通配符:在写入时保证类型安全,因为只能写入 TT 的子类。

超类:= 父类 = 基类

参考:Java——重写(Override)与重载(Overload)(概念理解+应用举例)_java重写是什么意思-CSDN博客

重载:

同一个方法根据输入数据的不同,做出不同的处理

class Overloading {
	public int test() {
		System.out.println("test1");
        return 1;
    }
    public void test(int a) {
        System.out.println("test2");
    }   
    //以下两个方法中参数类型的顺序不同
    public String test(int a,String s) {
        System.out.println("test3");
        return "test方法被重载第二次";
    }   
    public String test(String s,int a) {
        System.out.println("test4");
        return "test方法被重载第三次";
    }
}
public class Overload {
	public static void main(String[] args) {
		Overloading a=new Overloading();
        System.out.println(a.test());
        a.test(1);
        System.out.println(a.test(1,"test3"));
        System.out.println(a.test("test4",1));
	}
}

重写:

当子类继承父类相同的方法时,输入数据一样,但要做出有别于父类的响应时,要覆盖父类的方法

class AnimalPark {
	public void move() {
		System.out.println("动物可以移动!");
	}
}
class Dogs extends AnimalPark {
	public void move() {
		System.out.println("狗可以跑和跳!");
	}
}
public class Override {
	public static void main(String[] args) {
		AnimalPark a=new AnimalPark();    //
		AnimalPark b=new Dogs();          //
		a.move();
		b.move();
	}
}

标签:Java,ArrayList,通配符,接口,类型,base,泛型,public
From: https://blog.csdn.net/m0_54463709/article/details/139294873

相关文章

  • 报错信息:Unable to make field private final java.lang.Class java.lang.invoke.Seri
    jdk版本与当前MyBatisPlus版本不兼容解决方法:1.升级MyBatisPlus的版本。2.或者使用以下方法--add-opensjava.base/java.lang.invoke=ALL-UNNAMED......
  • (JAVA)设计模式-适配器模式
    模式的定义和特点:适配器模式(Adapter)是一种将一个类的接口转换成客户希望的另外一个接口的设计模式,可以提高代码的复用性和灵活性。结构与实现:定义一个适配器类来实现业务接口,再继承现有组件库中已经存在的组件。示例:创建业务接口类:点击查看代码publicinte......
  • Java中的网络编程:构建稳健的分布式应用
            网络编程是Java开发中至关重要的一部分,特别是在构建分布式系统和网络应用程序时。Java提供了丰富的网络编程API和库,使开发者能够轻松创建各种网络应用。本文将介绍Java中的网络编程基础、常用的网络通信协议、以及如何利用Java构建稳健的分布式应用。####1.......
  • Java中的Lambda表达式与函数式接口:简化代码与提升效率
            Lambda表达式自Java8引入以来,已成为Java编程中提高代码简洁性与效率的一种重要特性。Lambda表达式允许你以匿名函数的方式来编写方法,使代码更简洁,增强了集合库的功能,尤其是在处理集合操作时。本文将探讨Lambda表达式的基本概念、函数式接口的用途,以及如何在实......
  • Java多线程编程:提高程序性能与响应性
            多线程编程是利用计算机的多核心优势来提高程序的性能和响应性的重要手段之一。在Java中,通过多线程可以实现同时执行多个任务,充分利用CPU资源,加速程序的运行。本文将深入探讨Java多线程编程的基本概念、常用类库、并发问题以及最佳实践。####1.多线程基础概......
  • java选择题
    题目来自牛客网1.为初始化其成员变量,每个类都定义的方法是()A.方法B.mainC.构造方法D.对象正确答案:C.构造方法构造方法是一种特殊的方法,用于在创建对象时初始化对象的状态。它与类名相同,没有返回类型,并且在创建对象时自动调用。构造方法可以有参数,允许在创建对象时传递初......
  • Java泛型中<? extends E>和<? super E>的区别
    <?extendsE>      <?extendsE>是UpperBound(上限)的通配符,用来限制元素的类型的上限,比如List<?extendsFruit>fruits;表示集合中的元素类型上限为Fruit类型,即只能是Fruit或者Fruit的子类,因此对于下面的赋值是合理的fruits=newArrayList<Fruit>();fruits......
  • GraalVM - Java8 Linux AMD64
    使用GraalVM在linuxamd64环境下编译Java8程序的步骤主要包括:下载GraalVM下载native-image安装native-image编译程序1.下载GraalVM可以通过Github的release页面直接下载(往回找,找到支持java8的graalvm-ce-java8-linux-amd64-20.3.2.tar.gz)https://github.com/graalvm/gra......
  • Java文件IO
    Whitegraces:个人主页......
  • Java 集合中的组内平均值计算
    在Java开发中,集合(Collection)是一个重要的数据结构,广泛应用于各种场景。计算集合中的组内平均值是一个常见的操作,尤其是在数据分析、统计和处理时更为重要。本文将深入探讨如何使用Java来计算集合中的组内平均值,涵盖基本概念、具体实现、优化策略和实用示例。集合框架概述Java......