前言
在java中,由于基本类型不是继承⾃object,为了在泛型中可以⽀持基本类型,java给每个基本类型都对应了⼀个包装类型,有些情况下只有接收泛型才可以完成其功能
包装类
| 基本数据类型 | 包装类 |
|---|---|
| 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);
//拆箱,将其包装类型的数据放入基本数据类型中
int i = a1.intvalue();
int j = a2.intvalue();
system.out.println(a1);
system.out.println(a2);
system.out.println(i);
system.out.println(j);
}
}
运行结果如下

上面我们在装箱和拆箱的时候,都要利用其官方的方法,这样导致代码量增多
自动装箱和拆箱
public class test {
public static void main(string[] args) {
int a = 10;
integer a1 = (integer) a;//强制类型转换
integer a2 = a;//自动类型转换
int a3 = a1;//自动类型转换
int a4 = (int) a2;//强制类型转换
system.out.println(a1);
system.out.println(a2);
system.out.println(a3);
system.out.println(a4);
}
}
这里可以强制类型转换,也可以自动类型转换,java是提供了这个机制
运行结果如下

基本类型和包装类型其实并不完全相同
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);
}
}
运行结果如下

这里是自动调用其integer.valueof方法
这里如果换成普通数据类型这里就相同了,就输出两个true,但是换成包装类型,这里的结果就变了,为什么呢,这就要看看其包装类型的存储了

因为这里的传入值如果为[-128,127]放其给定好的数组中,反之则new一个新对象,所以这里超过其这个范围两个地址不相同了,所以这里的127返回true,128返回false
泛型
泛型的概念
以前在写方法的时候,都是使用的基本类型,这样此方法只可以用于这一种类型,那可不可以创建一个方法可以让多种数据类型都可以使用呢,这就引入了泛型,就是其可以使用多种类型
我们可以先自己定义一个数组可以存放多种类型的数据,里面有存放和获取一个下标数值
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));
}
}
运行结果如下

但是要注意创建一个对象以后,添加了一种类型的数据,就不可以在添加另外一种数据了
一个数组中的元素类型要一致

就像上面已经添加了int类型就说明这里是int类型数组,因此不可以在添加其他数据类型,这里如果在添加string类型就会出错
泛型的使用
定义一个泛型类
class 泛型类名称<类型形参列表> {
} // 这⾥可以使⽤类型参数
也可以放多种类型
class classname<t1, t2, …, tn> {
}
这个泛型方法的使用
泛型类<类型实参> 变量名= new 泛型类<类型实参>(构造⽅法实参);
//定义一个泛型类引用,并实例化一个对象
例如
arraylist< integer > list = new arraylist<>();//实例化一个integer数据类型的列表
这里在实例化的时候<>内不用在写是什么类型,编译器会从前面推导出来
有了这个上面的代码就可以改为
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包装类型的数组
//就不可以存储其以外的数据了
myarray<integer> myarray = new myarray();
myarray.setval(0,1);
//myarray.setval(1,"124");
system.out.println(myarray.getval(0));
}
}
这里在创建对象的时候就确定了是什么数据类型的数组
并且这里的数组数据类型只可以是包装类型
1.如果写成普通数据类型就会报错,这里需要的是包装类型

2.确定了数据类型就不可以存放其他数据类型了

交换的泛型方法
public class test {
public static void main(string[] args) {
integer[] arr ={1,2,3};
swap(arr,1,2);
}
//这里静态泛型方法前面要说明是什么类型
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> 代表占位符,表⽰当前类是⼀个泛型类 e表⽰element, k表⽰key , v表⽰value ,n表⽰number ,t表⽰type 2.创建对象的时候就确认其数组数据类型,并且只可以是包装类型 3.确认数据类型就不可以在其数组放入其他数据类型的数据了
泛型的上界
在定义泛型类的时候有时候我们要对其传入数据类型进行限制,于是就引出了泛型的上界
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;
}
}
例如上面这个类就是上界是number
也就是这里是要是int double float类型等等数字类型
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数字,如果不是数字类型的包装类型就会报错,例如下面传入引用数据类型就会报错

通配符
通配符概念
?也可以用于泛型的使用,也就是通配符
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());
}
}
运行结果如下

我们发现上面的fun函数并不是泛型,只可以打印和接收string类型,如果是其他的类型就会报错,这明显不符合我们的需求,我们要其可以接收和打印多种类型
如果这里传入integer类型就会报错

因此这时候我们就可以使用通配符?
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);
}
//传入什么类型,这个就是什么类型
public static void fun(message<?> message){
system.out.println(message.getmessage());
}
}
运行结果如下

其实这里我们使用上面的泛型也可以
public static<t> void fun(message<t> message){
system.out.println(message.getmessage());
}
通配符上界
<?extend 上界>
定义了一个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());//这个超越了上界
}
//fun用于打印
//这里表示只可以传入fruit及其子类
public static void fun(plate<? extends fruit> plate){
// plate.setplate(new apple());
// plate.setplate(new banana());
//在这里不可以添加元素,因为这里的plate不知道是那个的子类,报错
system.out.println(plate.getplate());
}
}
运行结果如下

这里的fun函数参数的上界为fruit,所以其只可以接收,fruit及其子类
如果传入food,是fruit的父类肯定报错,超越了上界

并且不可以在其fun函数里,来进行添加元素
因为这里的plate是那个子类我们并不知道,不知道添加什么类型的元素

通配符下界
<? 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());
}
}
运行结果如下

这里下界为fruit,只可以传入fruit及其父类
不可以传入其子类

由于这里fun函数接收的下界为fruit,所以其是可以在里面添加其fruit子类对象
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());
}
虽然可以添加,但是不可以接收,因为不知道是用哪一个父类来接收,fruit可能有很多父类

到这里就结束了。
以上就是一文详解java中的包装类和泛型的详细内容,更多关于java包装类和泛型的资料请关注代码网其它相关文章!
发表评论