java泛型初阶和包装类

这篇具有很好参考价值的文章主要介绍了java泛型初阶和包装类。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1 包装类

在Java中,由于基本类型不是继承自Object,为了在泛型代码中可以支持基本类型,Java给每个基本类型都对应了
一个包装类型。

6 泛型如何编译的

6.1 擦除机制

那么,泛型到底是怎么编译的?这个问题,也是曾经的一个面试问题。泛型本质是一个非常难的语法,要理解好他
还是需要一定的时间打磨。

通过命令:javap -c 查看字节码文件,所有的T都是Object。
java泛型初阶和包装类

在编译的过程当中,将所有的T替换为Object这种机制,我们称为:擦除机制。

Java的泛型机制是在编译级别实现的。编译器生成的字节码在运行期间并不包含泛型的类型信息。

有关泛型擦除机制的文章截介绍:https://zhuanlan.zhihu.com/p/51452375

提出问题:

1、那为什么,T[] ts = new T[5]; 是不对的,编译的时候,替换为Object,不是相当于:Object[] ts = new
Object[5]吗?

2、类型擦除,一定是把T变成Object吗?

6.2 为什么不能实例化泛型类型数组

小结: 基类数组不能直接强制类型转换赋值给子类数组,因为基类数组可能存在其他类型的子类

讲解步骤:

  • 抛出问题代码
  • 分析代码错误原因
  • 具体解释错误原因
  • 解决问题
  • 开发中正确写法

代码1:

class MyArray<T> {
	public T[] array = (T[])new Object[10];//泛型类型数组
	
	public T getPos(int pos) {
		return this.array[pos];
	}
	
	public void setVal(int pos,T val) {
	this.array[pos] = val;
		}
	
	public T[] getArray() {
		return array;
	}
}
public static void main(String[] args) {
		MyArray<Integer> myArray1 = new MyArray<>();
			Integer[] strings = myArray1.getArray();//erro
}	
/*
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
at TestDemo.main(TestDemo.java:31)
*/

原因:擦除替换后, 将Object[]分配给Integer[]引用,程序报错。

// 替换前
public T[] getArray() {
	return array;
}
// 替换后
public Object[] getArray() {
	return array;
}

通俗讲就是:返回的Object数组里面,可能存放的是任何的数据类型,可能是String,可能是Person,运行的时
候,直接转给Integer类型的数组,编译器认为是不安全的。

如下两点详细解释

1.如下代码,在java中,new必须指定确定类型

class MyArray<T> {
    //public T[] array = (T[])new Object[10];
    public T[] array = new T[2];
    public T getPos(int pos) {
        return this.array[pos];
    }
    public void setVal(int pos,T val) {
        this.array[pos] = val;
    }
    public T[] getArray() {
        return array;
    }
}

2.在Java中,不能将Object类型的数组分配给子类的数组,因为这会违反Java的类型安全性规则。如果可以这样做,那么子类数组可能包含其它类型的元素,从而导致类型转换异常或者其他运行时错误。要将一个Object类型的数组分配给子类的数组,需要使用强制类型转换并确保所有元素都是正确的子类类型。
例如:

ojbecj对象是所有类的基类,下面是基类与子类的例子,假设有一个父类Animal和两个子类Cat和Dog,如果想要将一个Object类型的Animal数组分配给一个Cat类型的数组,需要进行以下强制类型转换:

    public static void main(String[] args) {
 // erro1:
      Animal[] animalArray = new Animal[2];
      Cat[] catArray = (Cat[]) animalArray;//erro
    }
     // 报错:
		//Exception in thread "main" java.lang.ClassCastException: Dog cannot be cast to Cat
		//at genericArray.main(genericArray.java:68)

但是这样做会导致运行时错误,因为animalArray实际上并不是一个Cat数组,其中可能包含其他类型的Animal对象。

正确的做法是,使用for循环逐一将Object类型的元素转换为Cat类型,并添加到Cat类型的新数组中,例如:

    public static void main(String[] args) {
//  success:
        Animal[] animalArray = new Animal[2];
        Cat[] catArray = new Cat[2];
        for (int i = 0; i < animalArray.length; i++) {
            catArray[i] = (Cat) animalArray[i]; // 进行强制类型转换
        }
    }

这样可以确保每个元素都被正确地转换为Cat类型。但是需要注意,如果animalArray中包含了除Animal以外的其它类型的对象,则会在转换时抛出ClassCastException异常。

    public static void main(String[] args) {
//  erro2:        
       Animal[] animalArray = new Animal[2];
       animalArray[1] = new Dog(); // Animal[]数组包含了其他Animal子类
    	Cat[] catArray = new Cat[2];
       for (int i = 0; i < animalArray.length; i++) {
           catArray[i] = (Cat) animalArray[i]; // 进行强制类型转换
           //erro i==1时,Dog错误类型转换
      }
 // 报错:
//Exception in thread "main" java.lang.ClassCastException: Dog cannot be cast to Cat
	//at genericArray.main(genericArray.java:68)

解决办法: 【了解即可,开发中不会用到】

  • 有点神奇!通过反射创建,指定类型的数组
class MyArray1<T> {
    public T[] array;

    public MyArray1() {
    }
    public MyArray1(Class<T> clazz, int capacity) {
        array = (T[]) Array.newInstance(clazz, capacity);
    }
    public T getPos(int pos) {
        return this.array[pos];
    }
    public void setVal(int pos,T val) {
        this.array[pos] = val;
    }
    public T[] getArray() {
        return array;
    }
}

实际开发是这样的:

class MyArray3<T> {
    //public T[] array = (T[])new Object[10];
    public Object[] array = new Object[2];
    public T getPos(int pos) {
        return (T)array[pos];
    }
    public void setVal(int pos,T val) {
        this.array[pos] = val;
    }
    public Object[] getArray() {
        return array;
    }
}
public class genericArray {
    public static void main(String[] args) {
        MyArray<Integer> myArray = new MyArray<>();
        myArray.setVal(0,1);
        myArray.setVal(1,0);
        Object a = myArray.getPos(0);
        System.out.println(a);
        // 不用转换类型也可以的,因为返回的就是object
        Object b = (Object)myArray.getPos(1);
        System.out.println(b);
        //Integer[] int_array = myArray.getArray(); erro 基类数组不能给子类
        // 获取数组后,访问数组元素需要强制转换.
        Object[] int_array = myArray.getArray();
        System.out.println((Integer)int_array[0]);
    }
}

7 泛型的上界

在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束。

7.1 语法

class 泛型类名<泛型新参 extend 类型边界>{

}

具体意思通过例子说明。

7.2 示例

public class MyArray<E extends Number> {
........

}

接受 Number 的子类型作为 E 的类型实参

MyArray<Integer> l1; // 正常,因为 Integer 是 Number 的子类型
MyArray<String> l2; // 编译错误,因为 String 不是 Number 的子类型
error: type argument String is not within bounds of type-variable E
MyArrayList<String> l2;
^
where E is a type-variable:
E extends Number declared in class MyArrayList

了解: 没有指定类型边界 E,可以视为 E extends Object

7.3 复杂示例


// #2 语法规定只允许有使用Comparable接口的类型
class Alg<T extends Comparable<T>>{

    public T findMax(T[] array){
        T max = array[0];
        for(int i=1;i<array.length;i++){
            // if( max < array[i]) #1 erro : 引用类型无法比较
            // 只能实现接口compareTO()
            if(max.compareTo(array[i])<0)
            {
                max = array[i];
            }
        }
        return max;
    }
}
public class Main {
    public static void main(String[] args) {
        Alg<Integer> alg = new Alg();
        Integer[] array = {1,2,3,4,5};
        // 根据array自动类型推导
        System.out.println(alg.findMax(array));
        // 新语法 <类型> 指定类型
        System.out.println(alg.<Integer>findMax(array));
        // Alg<int> alg2 = new Alg(); // erro
        //#3
        // Alg<int> alg2 = new Alg(); // erro
    }
}

8 泛型方法

8.1 定义语法

方法限定符 <类型形参列表> 返回值类型 方法名称(形参列表) { ... }

8.2 示例

静态的泛型方法 需要在static后用<>声明泛型类型参数文章来源地址https://www.toymoban.com/news/detail-458400.html

class Alg1{

    public static<T extends Comparable<T>> T findMax(T[] array){
        T max = array[0];
        for(int i=1;i<array.length;i++){
            // if( max < array[i]) #1 erro : 引用类型无法比较
            // 只能实现接口compareTO()
            if(max.compareTo(array[i])<0)
            {
                max = array[i];
            }
        }
        return max;
    }
}

 public class Main {
     public static void main(String[] args) {
         Integer[] array = {1,2,3,4,5};

         // 根据array自动类型推导
         System.out.println(Alg1.findMax(array));
         // 新语法 <类型> 指定类型
         System.out.println(Alg1.<Integer>findMax(array));
     }
  }

8.3 使用示例-可以类型推导

 public class Main {
     public static void main(String[] args) {
         Integer[] array = {1,2,3,4,5};

         // 根据array自动类型推导
         System.out.println(Alg1.findMax(array));

     }
  }

8.4 使用示例-不使用类型推导

 public class Main {
     public static void main(String[] args) {
         Integer[] array = {1,2,3,4,5};


         // 新语法 <类型> 指定类型
         System.out.println(Alg1.<Integer>findMax(array));
     }
  }

到了这里,关于java泛型初阶和包装类的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 谈谈包装类与泛型

    目录 包装类 基本数据类型与对应的包装类 装箱和拆箱 装箱 拆箱 泛型 什么是泛型 泛型的语法与使用 泛型的编译 擦除机制 泛型的上界 泛型方法 提到泛型的话,我们就先提一下包装类吧! 在Java中,由于基本类型不是继承自Object,为了在 泛型代码 中可以 支持基本类型 ,

    2024年02月06日
    浏览(29)
  • JAVA包装类和基本数据类型------JAVA入门基础教程

    public class WrapperTest {     public static void main(String[] args)     {         int i1 = 10;         Integer i11 = new Integer(i1);         System.out.println(i11);         float f1 = 12.3F;         f1 = 32.2F;         Float ff1 = new Float(f1);         System.out.println(ff1);         String s1 = \\\"32.1\\\";         F

    2024年02月02日
    浏览(29)
  • 【数据结构】复杂度&包装&泛型

    目录 1.时间和空间复杂度 1.1时间复杂度 1.2空间复杂度 2.包装类 2.1基本数据类型和对应的包装类 2.2装箱和拆箱 //阿里巴巴面试题 3.泛型 3.1擦除机制  3.2泛型的上界 定义 :一个算法所花费的时间与其语句的执行次数成正比,算法中的基本操作的 执行次数 ,为算法的时间复杂

    2024年02月03日
    浏览(28)
  • 【数据结构】 简单认识包装类与泛型

    在Java中,由于基本类型不是继承自Object,为了在 泛型代码 中可以支持基本类型,Java给每个基本类型都对应了一个包装类型。 除了 Integer 和 Character, 其余基本类型的包装类都是首字母大写。 装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换

    2024年02月12日
    浏览(34)
  • Java 中有了基本类型为什么还需要包装类?

    Java 中有8种基本数据类型,这些基本类型又都有对应的包装类。 分类 基本数据类型 包装类 布尔型 boolean Boolean 整型 byte Byte short Short int Integer long Long 字符型 char Character 浮点型 float Float double Double 因为 Java 是一种面向对象语言,很多地方都需要使用对象而不是基本数据类型。

    2024年02月14日
    浏览(30)
  • C++——模板初阶与泛型编程

    🌸作者简介: 花想云 ,在读本科生一枚,致力于 C/C++、Linux 学习。 🌸 本文收录于 C++系列 ,本专栏主要内容为 C++ 初阶、C++ 进阶、STL 详解等,专为大学生打造全套 C++ 学习教程,持续更新! 🌸 相关专栏推荐: C语言初阶系列 、 C语言进阶系列 、 数据结构与算法 本章我们

    2023年04月17日
    浏览(29)
  • 【C++】C++泛型编程 | 模板初阶

      🧑‍🎓 个人主页:简 料   🏆 所属专栏:C++   🏆 个人社区:越努力越幸运社区   🏆 简       介: 简料简料,简单有料~在校大学生一枚,专注C/C++/GO的干货分享,立志成为您的好帮手 ~ C/C++学习路线 (点击解锁) ❤️ C语言 ❤️ 初阶数据结构与算法 ❤️ C++ ❤️

    2024年02月08日
    浏览(65)
  • 【C++基础(十)】C++泛型编程--模板初阶

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:C++从入门到精通⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习C++   🔝🔝 在学习数据结构时会遇见以下的情况 数据结构中存储的类型往往不能确定 所以在实现数据结构时往往是这样做的 在写代码时用DateType来表

    2024年02月13日
    浏览(22)
  • 【C++初阶】八、初识模板(泛型编程、函数模板、类模板)

    ========================================================================= 相关代码gitee自取 : C语言学习日记: 加油努力 (gitee.com)  ========================================================================= 接上期 : 【C++初阶】七、内存管理 (C/C++内存分布、C++内存管理方式、operator new / delete 函数、定位new表

    2024年02月04日
    浏览(32)
  • 包装类、多线程的基本使用

    基本类型 包装类 byte Byte short Short int Integer long Long float Float double Double char Character boolean Boolean 2.1Integer基本使用 Boolean包装类中 , 底层调用了parseBoolean(String s) , 在parseBoolean中调用了equals.IgnoreCase(s) , 忽略了大小写 2.2装箱and拆箱 2.3自动拆箱装箱 在操作的过程中,基本类型和包装

    2024年02月09日
    浏览(25)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包