一文詳解Java中的包裝類和泛型
前言
在Java中,由于基本類型不是繼承?Object,為了在泛型中可以?持基本類型,Java給每個(gè)基本類型都對(duì)應(yīng)了?個(gè)包裝類型,有些情況下只有接收泛型才可以完成其功能
包裝類
| 基本數(shù)據(jù)類型 | 包裝類 |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| char | Character |
| boolean | Boolean |
這里的除了int 和char 類型的包裝類是Integer和Character 其他的都是其首字母大寫
裝箱和拆箱
public class Test {
public static void main(String[] args) {
int a = 10;
//裝箱操作 將a的值放入包裝類型中
Integer a1 = Integer.valueOf(a);
Integer a2 = new Integer(a);
//拆箱,將其包裝類型的數(shù)據(jù)放入基本數(shù)據(jù)類型中
int i = a1.intValue();
int j = a2.intValue();
System.out.println(a1);
System.out.println(a2);
System.out.println(i);
System.out.println(j);
}
}
運(yùn)行結(jié)果如下

上面我們?cè)谘b箱和拆箱的時(shí)候,都要利用其官方的方法,這樣導(dǎo)致代碼量增多
自動(dòng)裝箱和拆箱
public class Test {
public static void main(String[] args) {
int a = 10;
Integer a1 = (Integer) a;//強(qiáng)制類型轉(zhuǎn)換
Integer a2 = a;//自動(dòng)類型轉(zhuǎn)換
int a3 = a1;//自動(dòng)類型轉(zhuǎn)換
int a4 = (int) a2;//強(qiáng)制類型轉(zhuǎn)換
System.out.println(a1);
System.out.println(a2);
System.out.println(a3);
System.out.println(a4);
}
}
這里可以強(qiáng)制類型轉(zhuǎn)換,也可以自動(dòng)類型轉(zhuǎn)換,Java是提供了這個(gè)機(jī)制
運(yùn)行結(jié)果如下

基本類型和包裝類型其實(shí)并不完全相同
public class Test {
public static void main(String[] args) {
Integer a1 = 10;
Integer a2 = 10;
Integer a3 = 128;
Integer a4 = 128;
System.out.println(a1==a2);
System.out.println(a3==a4);
}
}
運(yùn)行結(jié)果如下

這里是自動(dòng)調(diào)用其Integer.valueOf方法
這里如果換成普通數(shù)據(jù)類型這里就相同了,就輸出兩個(gè)true,但是換成包裝類型,這里的結(jié)果就變了,為什么呢,這就要看看其包裝類型的存儲(chǔ)了

因?yàn)檫@里的傳入值如果為[-128,127]放其給定好的數(shù)組中,反之則new一個(gè)新對(duì)象,所以這里超過(guò)其這個(gè)范圍兩個(gè)地址不相同了,所以這里的127返回true,128返回false
泛型
泛型的概念
以前在寫方法的時(shí)候,都是使用的基本類型,這樣此方法只可以用于這一種類型,那可不可以創(chuàng)建一個(gè)方法可以讓多種數(shù)據(jù)類型都可以使用呢,這就引入了泛型,就是其可以使用多種類型
我們可以先自己定義一個(gè)數(shù)組可以存放多種類型的數(shù)據(jù),里面有存放和獲取一個(gè)下標(biāo)數(shù)值
class MyArray{
public Object[] array = new Object[10];
public Object getval(int index){
return array[index];
}
public void setval(int index,int val){
this.array[index] = val;
}
}
public class Test {
public static void main(String[] args) {
MyArray myArray = new MyArray();
myArray.setval(0,1);
System.out.println(myArray.getval(0));
}
}
運(yùn)行結(jié)果如下

但是要注意創(chuàng)建一個(gè)對(duì)象以后,添加了一種類型的數(shù)據(jù),就不可以在添加另外一種數(shù)據(jù)了
一個(gè)數(shù)組中的元素類型要一致

就像上面已經(jīng)添加了int類型就說(shuō)明這里是int類型數(shù)組,因此不可以在添加其他數(shù)據(jù)類型,這里如果在添加String類型就會(huì)出錯(cuò)
泛型的使用
定義一個(gè)泛型類
class 泛型類名稱<類型形參列表> {
} // 這?可以使?類型參數(shù)
也可以放多種類型
class ClassName<T1, T2, …, Tn> {
}
這個(gè)泛型方法的使用
泛型類<類型實(shí)參> 變量名= new 泛型類<類型實(shí)參>(構(gòu)造?法實(shí)參);
//定義一個(gè)泛型類引用,并實(shí)例化一個(gè)對(duì)象
例如
ArrayList< Integer > list = new ArrayList<>();//實(shí)例化一個(gè)Integer數(shù)據(jù)類型的列表
這里在實(shí)例化的時(shí)候<>內(nèi)不用在寫是什么類型,編譯器會(huì)從前面推導(dǎo)出來(lái)
有了這個(gè)上面的代碼就可以改為
class MyArray<T>{
public Object[] array = new Object[10];
public T getval(int index){
return (T)array[index];
}
public void setval(int index,int val){
this.array[index] = val;
}
}
public class Test {
public static void main(String[] args) {
//這里指定了是Integer包裝類型的數(shù)組
//就不可以存儲(chǔ)其以外的數(shù)據(jù)了
MyArray<Integer> myArray = new MyArray();
myArray.setval(0,1);
//myArray.setval(1,"124");
System.out.println(myArray.getval(0));
}
}
這里在創(chuàng)建對(duì)象的時(shí)候就確定了是什么數(shù)據(jù)類型的數(shù)組
并且這里的數(shù)組數(shù)據(jù)類型只可以是包裝類型
1.如果寫成普通數(shù)據(jù)類型就會(huì)報(bào)錯(cuò),這里需要的是包裝類型

2.確定了數(shù)據(jù)類型就不可以存放其他數(shù)據(jù)類型了

交換的泛型方法
public class Test {
public static void main(String[] args) {
Integer[] arr ={1,2,3};
swap(arr,1,2);
}
//這里靜態(tài)泛型方法前面要說(shuō)明是什么類型
public static <T> void swap(T[] array,int i,int j){
T tem = array[i];
array[i] = array[j];
array[j] = tem;
}
}
這里前面的T是不可以省略的,用于確定其是什么類型

1.類名后的 <T> 代表占位符,表?當(dāng)前類是?個(gè)泛型類 E表?Element, K表?Key , V表?Value ,N表?Number ,T表?Type 2.創(chuàng)建對(duì)象的時(shí)候就確認(rèn)其數(shù)組數(shù)據(jù)類型,并且只可以是包裝類型 3.確認(rèn)數(shù)據(jù)類型就不可以在其數(shù)組放入其他數(shù)據(jù)類型的數(shù)據(jù)了
泛型的上界
在定義泛型類的時(shí)候有時(shí)候我們要對(duì)其傳入數(shù)據(jù)類型進(jìn)行限制,于是就引出了泛型的上界
class 泛型類名稱<類型形參 extends 類型邊界> {
…
}
例如上面
public class MyArray< E extends Number> {
…
}
//這里表示上界是Number
例如
class MyArray<T extends Number>{
public Object[] array = new Object[10];
public T getval(int index){
return (T)array[index];
}
public void setval(int index,int val){
this.array[index] = val;
}
}
例如上面這個(gè)類就是上界是Number
也就是這里是要是int double float類型等等數(shù)字類型
public class Test {
public static void main(String[] args) {
MyArray<Integer> myArray = new MyArray<>();
MyArray<Double> myArray1 = new MyArray<>();
MyArray<Float> myArray2 = new MyArray<>();
}
}
這里要求的上界是Number數(shù)字,如果不是數(shù)字類型的包裝類型就會(huì)報(bào)錯(cuò),例如下面?zhèn)魅胍脭?shù)據(jù)類型就會(huì)報(bào)錯(cuò)

通配符
通配符概念
?也可以用于泛型的使用,也就是通配符
class Message<T>{
private T message;
public T getMessage() {
return message;
}
public void setMessage(T message) {
this.message = message;
}
}
public class Test {
public static void main(String[] args) {
Message<String> message = new Message<>();
message.setMessage("hello world");
fun(message);
}
public static void fun(Message<String> message){
System.out.println(message.getMessage());
}
}
運(yùn)行結(jié)果如下

我們發(fā)現(xiàn)上面的fun函數(shù)并不是泛型,只可以打印和接收String類型,如果是其他的類型就會(huì)報(bào)錯(cuò),這明顯不符合我們的需求,我們要其可以接收和打印多種類型
如果這里傳入Integer類型就會(huì)報(bào)錯(cuò)

因此這時(shí)候我們就可以使用通配符?
public class Test {
public static void main(String[] args) {
Message<String> message = new Message<>();
message.setMessage("hello world");
fun(message);
Message<Integer> message1 = new Message<>();
message1.setMessage(1111);
fun(message1);
}
//傳入什么類型,這個(gè)就是什么類型
public static void fun(Message<?> message){
System.out.println(message.getMessage());
}
}
運(yùn)行結(jié)果如下

其實(shí)這里我們使用上面的泛型也可以
public static<T> void fun(Message<T> message){
System.out.println(message.getMessage());
}
通配符上界
<?extend 上界>
定義了一個(gè)Food類

class Food{
}
class Fruit extends Food{
}
class Banana extends Fruit{
}
class Apple extends Fruit{
}
class Plate<T>{
private T plate;
public T getPlate() {
return plate;
}
public void setPlate(T plate) {
this.plate = plate;
}
}
public class Test {
public static void main(String[] args) {
//這里的類型要為Fruit或者其子類
Plate<Apple> plate1 = new Plate<>();
plate1.setPlate(new Apple());
fun(plate1);
Plate<Banana> plate2 = new Plate<>();
plate2.setPlate(new Banana());
fun(plate2);
// fun(new Food());//這個(gè)超越了上界
}
//fun用于打印
//這里表示只可以傳入Fruit及其子類
public static void fun(Plate<? extends Fruit> plate){
// plate.setPlate(new Apple());
// plate.setPlate(new Banana());
//在這里不可以添加元素,因?yàn)檫@里的plate不知道是那個(gè)的子類,報(bào)錯(cuò)
System.out.println(plate.getPlate());
}
}
運(yùn)行結(jié)果如下

這里的fun函數(shù)參數(shù)的上界為Fruit,所以其只可以接收,F(xiàn)ruit及其子類
如果傳入Food,是Fruit的父類肯定報(bào)錯(cuò),超越了上界

并且不可以在其fun函數(shù)里,來(lái)進(jìn)行添加元素
因?yàn)檫@里的plate是那個(gè)子類我們并不知道,不知道添加什么類型的元素

通配符下界
<? super 下界>
還是利用上面的
class Food{
}
class Fruit extends Food{
}
class Banana extends Fruit{
}
class Apple extends Fruit{
}
class Plate<T>{
private T plate;
public T getPlate() {
return plate;
}
public void setPlate(T plate) {
this.plate = plate;
}
}
public class Test {
public static void main(String[] args) {
Plate<Fruit> plate = new Plate<>();
plate.setPlate(new Fruit());
fun(plate);
Plate<Food> plate1 = new Plate<>();
plate1.setPlate(new Food());
fun(plate1);
// Plate<Apple> plate2 = new Plate<>();
// plate2.setPlate(new Apple());
// fun(plate2);//下界為Fruit,只可以傳入Fruit及其子類
}
public static void fun(Plate<? super Fruit> plate){
System.out.println(plate.getPlate());
}
}
運(yùn)行結(jié)果如下

這里下界為Fruit,只可以傳入Fruit及其父類
不可以傳入其子類

由于這里fun函數(shù)接收的下界為Fruit,所以其是可以在里面添加其Fruit子類對(duì)象
public static void fun(Plate<? super Fruit> plate){
plate.setPlate(new Apple());
plate.setPlate(new Banana());
plate.setPlate(new Fruit());
System.out.println(plate.getPlate());
}
雖然可以添加,但是不可以接收,因?yàn)椴恢朗怯媚囊粋€(gè)父類來(lái)接收,F(xiàn)ruit可能有很多父類

到這里就結(jié)束了。
以上就是一文詳解Java中的包裝類和泛型的詳細(xì)內(nèi)容,更多關(guān)于Java包裝類和泛型的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java面試題之HashMap 的 hash 方法原理是什么
那天,小二去蔚來(lái)面試,面試官老王一上來(lái)就問(wèn)他:HashMap 的 hash 方法的原理是什么?當(dāng)時(shí)就把裸面的小二給蚌埠住了,這篇文章將詳細(xì)解答該題目2021-11-11
Java反射通過(guò)Getter方法獲取對(duì)象VO的屬性值過(guò)程解析
這篇文章主要介紹了Java反射通過(guò)Getter方法獲取對(duì)象VO的屬性值過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02
Spring MVC攔截器(Interceptor)的定義和配置過(guò)程
這篇文章主要介紹了Spring MVC攔截器(Interceptor)的定義和配置過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-03-03
SpringBoot中干掉Whitelabel Error Page返回自定義內(nèi)容的實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot中干掉Whitelabel Error Page返回自定義內(nèi)容的實(shí)現(xiàn)方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01
java開(kāi)發(fā)中為什么雙重效驗(yàn)鎖要加volatile
這篇文章主要為大家介紹了java開(kāi)發(fā)中為什么雙重效驗(yàn)鎖要加volatile原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
JAVA 16位ID生成工具類含16位不重復(fù)的隨機(jī)數(shù)數(shù)字+大小寫
這篇文章主要介紹了JAVA 16位ID生成工具類含16位不重復(fù)的隨機(jī)數(shù)數(shù)字+大小寫,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
SpringBoot之自定義啟動(dòng)異常堆棧信息打印方式
這篇文章主要介紹了SpringBoot之自定義啟動(dòng)異常堆棧信息打印方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08

