包装类与泛型

泛型与包装类密切相关,在学习泛型前先了解了解包装类吧

包装类

包装类是对应着各种基本数据类型进行包装后产生的引用数据类型 ,是基本数据类型的plus版本。

为什么要设计包装类

因为 Java是一个面向对象的编程语言,但是Java中的八种基本数据类型却是不面向对象的,为了使用方便和解决这个不足,在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八种基本数据类型对应的类统称为包装类(Wrapper Class),包装类均位于java.lang包。

包装类的用处

对于包装类说,用途主要包含两种:

  1. 作为基本数据类型对应的类 类型存在,方便涉及到对象的操作。
  2. 包含每种基本数据类型的相关属性如最大值、最小值等,以及相关的操作方法。

1、基本数据类型和对应的包装类 

基本数据类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

除了 Integer 和 Character, 其余基本类型的包装类都是首字母大写。

2、包装类的使用

(1)装箱和拆箱

装箱:建立包装类对象,将对应基本数据类型放入对象属性中

int i=10;
Integer i1=Integer.valueOf(i);
Integer i2=new Integer(100);

拆箱:将包装类对象的属性值取出放入对应基本数据类型中

int j=i1.intValue();

自动装箱和自动拆箱

int i = 10;
Integer ii = i; // 自动装箱
Integer ij = (Integer)i; // 自动装箱
int j = ii; // 自动拆箱
int k = (int)ii; // 自动拆箱

(2)类内部常用方法

包装类作为类,有非常多的方法。下面以int-Integer为例,

        //parseInt方法: 数字字符串类型转成int类型
        String s="123";
        int i = Integer.parseInt(s);
        System.out.println("字符类型转成整型:"+i);
        //toString方法:int类型转成数字字符串类型
        int ii=123;
        String s2 = Integer.toString(ii);
        System.out.println("int类型转成数字字符串类型:"+s2);

细说valueOf ( ) 源码分析

public static Integer valueOf(int i) {
     assert IntegerCache.high>= 127;
     if (i >= IntegerCache.low&& i <= IntegerCache.high)
     return IntegerCache.cache[i+ (-IntegerCache.low)];
     return new Integer(i); 
}

注意方法体中,在返回之前对 int 作判断,IntegerCache.low=-128,IntegerCache.high=127.

127 >=  i >= -128,直接返回数组下标为i-(-128)的值,而不在这个范围时,返回新的对象

来两道常见面试题练练手吧

1、Java中 int 和 Intrger 的区别

  1. int 是基本类型,直接存数值;而integer引用数据类型。
  2. Int的声明不需要实例化,且变量声明后的初始值为0;Integer的是一个类,初始值为null,需要进行实例化,才能对变量数据进行处理。
  3. Integer类是int的包装类,实际开发中Integer被看成一个对象,可以进行数据转换等操作。

2、代码输出结果是? 

Integer a=100;
Integer b=100;
System.out.println(a==b);

Integer m=200;
Integer n=200;
System.out.println(m==n);

答案是   true    false 

泛型

1、概述

一般的类和方法,只能使用具体的类型: 要么是基本类型,要么是自定义的类。如果要编写可以应用于多种类型的 代码,这种刻板的限制对代码的束缚就会很大。----- 来源《 Java 编程思想》对泛型的介绍。
泛型是在 JDK1.5 引入的新的语法,通俗讲,泛型: 就是适用于许多许多类型从代码上讲,就是对类型实现了参数化。 那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式,然后在使用/调用时传入具体的类型)。

泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。

2、引出泛型

举个例子

 class MyArray {
            public Object[] array = new Object[10];

            public Object getPos(int pos) {
                return this.array[pos];
            }

            public void setVal(int pos, Object val) {
                this.array[pos] = val;
            }
        }

        MyArray myArray = new MyArray();
        myArray.setVal(0, 10);
        myArray.setVal(1, "hello");//字符串也可以存放

        String ret1=myArray.getPos(1);//error
        String ret2=(String) myArray.getPos(1);//运行正确

        System.out.println(myArray.array[0]);//打印10
        System.out.println(myArray.array[1]);//打印hello

 MyArray类中定义一个数组,类型为Object。

  • 在调用getPos与setPos时,参数既可以传入Integer类型也可以传入String等包装类。
  • 调用getPos取出结果,必须先强制类型转换。
虽然在这种情况下,当前数组任何数据都可以存放,但是,更多情况下,我们还是希望他只能够持有一种数据类 型。而不是同时持有这么多类型。所以,泛型的主要目的:就是指定当前的容器,要持有什么类型的对象。让编译 器去做检查。 此时,就需要把类型,作为参数传递。需要什么类型,就传入什么类型。

3、语法

class 泛型类名称 < 类型形参列表 > {
// 这里可以使用类型参数
}

注意:泛型只能接受类,所有的基本数据类型必须使用包装类 

代码举例

public class Test {
    public static void main(String[] args) {
        MyArray<Integer> myArray = new MyArray<>();
        myArray.set(0, 20);
        myArray.set(1, "hello");//error
        int ret=myArray.get(0);
        System.out.println(ret);
    }
}
public class MyArray <E>{
        Object[]arr=new Object[10];

        void set(int pos,E val){
            arr[pos]=val;
        }
       E get(int pos){
            return (E) arr[pos];
        }
}
类名后的 <T> 代表占位符,表示当前类是一个泛型类。
了解: 【规范】类型形参一般使用一个大写字母表示,常用的名称有:
E 表示 Element
K 表示 Key
V 表示 Value
N 表示 Number
T 表示 Type
S, U, V 等等 - 第二、第三、第四个类型

4、泛型的上界

占位符后extends 类(泛型的上界)表示参数既可以放父类,也可以放当前类的子类。 

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

class 泛型类名称 < 类型形参列表 > extends 继承类 /* 这里可以使用类型参数 */ {
// 这里可以使用类型参数
}
public class Test {
    public static void main(String[] args) {
        MyArray<People> myArray = new MyArray<>();
        People p1=new People();
        Student s1=new Student();
        myArray.set(0,p1);
        myArray.set(1,s1);
    }
}
public class MyArray <E extends People>{
        Object[]arr=new Object[10];

        void set(int pos, E val){
            arr[pos]=val;
        }
       E get(int pos){
            return (E) arr[pos];
        }
}
public class People {

}
public class Student extends People{

}

5、擦除机制

那么,泛型到底是怎么编译的?这个问题,也是曾经的一个面试问题。泛型本质是一个非常难的语法,要理解好他 还是需要一定的时间打磨。
在编译的过程当中,将所有的 T 替换为 Object 这种机制,我们称为: 擦除机制
Java 的泛型机制是在编译级别实现的。编译器生成的字节码在运行期间并不包含泛型的类型信息。
有关泛型擦除机制的文章截介绍:   https://zhuanlan.zhihu.com/p/51452375

6、泛型方法

方法限定符 < 类型形参列表 > 返回值类型 方法名称 ( 形参列表 ) { ... }
public class Util {
            //静态的泛型方法 需要在static后用<>声明泛型类型参数
            public static <E> void swap(E[] array, int i, int j) {
                E t = array[i];
                array[i] = array[j];
                array[j] = t;
            }
        }

包装类与泛型学习到这里。

  • 79
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 47
    评论
评论 47
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值