Java中的泛型(上)

一、为啥用泛型?

java泛型:

       泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。泛型就是操作类型的 占位符,即:假设占位符为T,那么此次声明的数据结构操作的数据类型为T类型。

二、泛型的意义:

1、可以对类型进行自动检查,仅仅用来类型检查(只在编译时期有效)

List<String> stringArrayList = new ArrayList<String>();
List<Integer> integerArrayList = new ArrayList<Integer>();
//编译时期传进来

//正确验证泛型结果后,会将泛型的相关信息擦除(泛型信息不会进入运行时段)
Class classStringArrayList = stringArrayList.getClass();
Class classIntegerArrayList = integerArrayList.getClass();

if(classStringArrayList.equals(classIntegerArrayList)){
    Log.d("泛型测试","类型相同");
}

//输出:D/泛型测试:类型相同

2、自动对类型进行转换

public class Fan <E>{
    private  E  value;
    private  int  a;
    private E number; // 定义泛型成员变量
        public Fan(E number) {
            this.number = number;
        }
        public E getNum() {
            return number;
        }
        public void setNum(E number) {
            this.number = number;
        }
        public void showType() {
            System.out.println("E 的实际类型是: " + number.getClass().getName());
        }
    public static void main(String[] args) {
         Fan<String> a=new Fan<String>("10");
        Fan<Integer> b=new Fan<Integer>(10);
         a.showType();
         b.showType();
    }

}

三、泛型的定义:

1、泛型类

     泛型的类型参数只能是类类型(包括自定义类),不能是简单类型 传入的实参类型需与泛型的类型参数类型相同。

注意:定义的泛型类,就一定要传入泛型类型实参么?并不是这样,在使用泛型的时候如果传入泛型实参,则会根据传入的泛型实参做相应的限制,此时泛型才会起到本应起到的限制作用。如果不传入泛型类型实参的话,在泛型类中使用泛型的方法或成员变量定义的类型可以为任何的类型。

2、泛型方法

    我们再次之前看到的泛型都是应用在整个类上,但同样可以包含参数化方法,而这个方法所在的类可以是
泛型类也可以不是泛型类。也就是说,是否拥有泛型方法与其所处的类是否是泛型类毫无关系。方法中,通过
指定类型参数,可以声明泛型方法,从而提高其可复用性。泛型方法的参数化类型列表放在方法类符的后面返
回值之前。

//例:交换函数 swap()
public static <T> void swap(T[] a,int i,int j){
T temp=a[i];
a[i] =a[j];
a[j] =temp;
}

(1)如果泛型方法的泛型参数与类型的泛型参数相同,编译器生成警告,因为方法的泛型参数隐藏

了外部类型的泛型参数。

class List<T>{

    <T>  void  fun(T value){
    }
}

( 2)直接可以通过”方法名()”的形式进行泛型方法的调用,编译器根据传入的方法实参推衍出类型形
参。
( 3)使用约束对泛型类型参数启到约束的作用。

//如extends compareable   

3、泛型接口

可以是一个或者多个接口。

interface MyArrayList<E>{
void add(E e);
}
interface MyList<K,V>{
void put(K key,V value);
}

4、泛型的约束

默认情况下,没有约束条件的泛型类型参数(Sample<T>)T 称为未绑定类型参数,当创建未绑定类型参
数的泛型类实例时,可以给参数类型指定任意类型。想要让泛型参数支持特定类型时,可以使用关键字 extends
interface MyArrayList<E>{
void add(E e);
}
interface MyList<K,V>{
void put(K key,V value);
}
例:交换函数 swap()
public static <T> void swap(T[] a,int i,int j){
T temp=a[i];
a[i] =a[j];
a[j] =temp;
}
或者 super 关键字对泛型参数进行约束。
(1) extends 主要限定泛型参数的上界(常见的使用如下):
<T extends 基类>://T 只能是基类或者基类的派生类
<T extends 基接口>; //T 只能是实现基接口的派生类

//按照顺序排序
class Sort<T>{// <T extends Comparable<T>>
private T[] elem;
@SuppressWarnings("unchecked")
public Sort(){
elem=(T[])new Object[2];
}
public void swap(){ //这个方法是否书写正确?得到正确结果代码该如何进行修改?
if(elem[0]>elem[1]){
if(elem[0].compareTo(elem[1])>0){ ①
T temp=elem[0];
elem[0]=elem[1];
elem[1]=temp;
}
}
}

5、通配符的使用

通配符的约束
<? extends 基类> :其中表明?未知类型限定为指定类或者指定类的派生类。指定上界。
<? super 派生类> :其中?未知类型限定为指定类或者指定类的基类。指定下界。

6、泛型错误:

不能直接new泛型数组 解决方法:(1(T[ ]new Object[10] 2、反射)

不能实例化泛型对象,因为不知道类型。

泛型参数不能是基本数据类型

7、总结:

编译时,会进行安全检测,会有类型擦除,没有定义上边界,默认擦除到Object。

类型之间有向上造型,泛型参数没有向上造型。

 

泛型问题一:java编译器先检查泛型的类型,然后再进行类型的擦除。

泛型问题二:泛型在引用变量之间传值过程中的应用。

泛型问题三:泛型中参数化类型不考虑继承关系。

泛型问题四:不能定义自定义泛型数组。

泛型问题五:泛型类型变量不能是基本数据类型。

泛型问题六:泛型在静态方法和静态变量中的问题。

泛型类中的静态方法和静态变量不可以使用泛型类所声明的泛型类型参数。

<think>好的,我现在需要帮助用户了解Java的使用方法和示例。首先,用户提供的引用内容提到类、方法、静态方法的以及伪的概念。我需要结合这些信息,整理出一个结构清晰的回答,并确保遵循系统级指令中的格式要求。 首先,用户可能对的基本概念不太清楚,所以需要先简单解释什么是,以及它的作用,比如类安全、代码复用等。然后,分点介绍的不同用法,比如类、方法、接口,每个部分都要有示例代码,并且代码中的数学表达式要用$...$格式,比如在解释方法时,如果有涉及类参数T,可以用$T$来表示。 接下来,需要注意引用内容中提到的伪,说明Java在编译时类擦除的特性,这可能会影响运行时无法获取的具体类。此外,用户可能想知道如何使用通配符和边界,比如上界和下界通配符,这部分需要给出示例,并正确应用LaTeX格式,比如$? extends Number$。 用户还提到静态方法的,需要特别注意静态方法不能使用类定义的,而必须自己声明,这点要强调,避免常见错误。示例代码需要正确展示如何在静态方法中定义类参数。 最后,生成相关问题时要考虑用户可能进一步想知道的内容,比如类擦除的影响、通配符的使用场景、与集合框架的结合,以及类边界的作用。确保每个问题都有针对性,帮助用户深入理解。 现在检查是否有遗漏,比如是否覆盖了所有引用中的要点,引用的标识是否正确添加,示例代码是否符合语法,数学表达式是否正确使用$符号。同时,确保回答结构清晰,分点明确,符合用户可见层的要求。</think>### Java使用方法及示例 Java用于实现**类参数化**,提高代码复用性和类安全性[^1]。以下是具体用法及示例: --- #### 一、类 定义类时声明类参数$T$,可在类中作为类使用: ```java public class Box<T> { private T content; public void setContent(T content) { this.content = content; } public T getContent() { return content; } } // 使用示例 Box<String> stringBox = new Box<>(); stringBox.setContent("Hello"); ``` --- #### 二、方法 在方法返回值前声明类参数$T$,可在非类中使用: ```java public class Utils { public static <T> T getMiddle(T[] arr) { return arr[arr.length/2]; } } // 调用示例 String[] names = {"Alice", "Bob", "Charlie"}; String middle = Utils.<String>getMiddle(names); // 返回"Bob" ``` --- #### 三、接口 定义接口时声明类参数,常用于集合类: ```java public interface List<T> { void add(T element); T get(int index); } // 实现示例 class StringList implements List<String> { // 必须使用String类实现方法 } ``` --- #### 四、类边界 限制范围: ```java public static <T extends Number> double sum(T a, T b) { return a.doubleValue() + b.doubleValue(); } // 只能传入Number及其子类 sum(10, 20.5); // 合法 sum("a", "b"); // 编译错误 ``` --- #### 五、通配符 处理未知类集合时使用: ```java // 上界通配符 void process(List<? extends Number> list) { /* 可读不可写 */ } // 下界通配符 void addNumbers(List<? super Integer> list) { /* 可写不可读 */ } ``` --- #### 关键特性 1. **类擦除**:编译后会被替换为Object或边界类[^3] 2. **静态方法限制**:静态方法需单独声明: ```java public static <T> void print(T item) { System.out.println(item); } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值