装箱与拆箱的意思分别是:
装箱:把基本数据类型转换成对应的包装类。
拆箱:把包装类转换成对应的基本数据类型。
八大基本数据类型对应的包装类都是引用类型。
目前的八大基本数据类型都有其对应的包装类:
基本数据类型 → 对应的包装类
byte → Byte
int → Integer
short → Short
long → Long
char → Character
float → Float
double → Double
boolean → Boolean
class Demo {
public static void main(String[] args) {
Integer num1 = 1; → 自动装箱
int num2 = num1; → 自动拆箱
}
}
其他类型的拆装箱雷同上述,此处略。
泛型:对数据类型的一种约束条件,泛型也是代码封装的一种思想。代码中使用泛型之后,可以极大的提高对于代码的复用性,可移植性,可操作性。
Java中泛型规定:
<自定义无意义英文大写单字母占位符>
一般常用: Type, Element, Key, Value
泛型可以约束:类、方法、接口
格式:
权限修饰符 [static] <自定义泛型> 返回值类型 方法名(形式参数列表) {
}
【重点】
java List list = new ArrayList<>();
泛型使用示例:
public class Demo2 {
public static void main(String[] args) {
Integer type = getType(1);
Float type2 = getType(3.14F);
Demo2 type3 = getType(new Demo2());
String type4 = getType("这方法有点东西哦~~~~");
Object obj = getType("123");
}
/**
* 带有自定义泛型 T 对应的方法
*
* @param 自定义泛型无意义英文单个大写字母占位符
* @param t T类型
* @return T类型
*/
public static <T> T getType(T t) {
return t;
}
public static Object getType(Object obj) {
return obj;
}
}
【注意】虽然Object用法与泛型用法相差不大,但是最重要的一点就是,使用Object做参数和返回值,在拿到返回值的时候会得到一个Object类型的数据,如果想要获得源数据类型,则必须要进行强制转型操作,这样会大大浪费效率【费事】。
有那么一大堆方法都要使用泛型,而且这些方法还有一定的关联性。使用类【封装】这些方法,将泛型的声明用于类名上,做到一个统一的约束过程。【始终强调的是方法!!!】
格式:
class 类名<自定义泛型无意义英文大写单个字母占位符> {
// 成员变量不推荐使用泛型,存在一定的隐患,操作不方便
// 成员方法可以使用类名声明的自定义泛型
// 静态成员方法是个坑!!!
}
类名使用泛型约束具体数据类型的格式【重点】泛型类型确定的时候是在创建对象的时候。
案例:
class Demo {
}
public class Demo2 {
public static void main(String[] args) {
/*
* 泛型约束当前 d 对象中所有的泛型都是String类型
*/
Demo<String> d = new Demo<>();
String info = d.getInfo("123");
System.out.println(info);
Demo<Dog> d2 = new Demo<>();
Dog info2 = d2.getInfo(new Dog());
System.out.println(info2);
}
}
class Dog{
}
/*
* 在带有泛型的类内,成员方法可以直接使用类声明的自定义泛型
*/
class Demo <T>{
public <T> T getInfo(T t) {
return t;
}
}
泛型数组只适用于引用数据类型,不适用于八大基本数据类型。
public class Test {
public static void main(String[] args) {
int[] a = {1,2,3,5,6};
printArray(a);--------------->错误的
Integer[] b = {1,2,3,5,6};
printArray(b);
}
public static <T> void printArray(T[] t) {
for (int i = 0; i < t.length; i++) {
System.out.println(t[i]);
}
}
}
接口:
成员变量:
缺省属性: public static final (定义时必须初始化)
成员方法:
缺省属性: public abstract (该方法没有方法体)
interface 接口名<自定义泛型无意义英文单个字母大写占位符> {
自定义泛型有且只能给方法使用!!!
}
【接口中的成员变量不能使用自定义泛型】
接口没有自己的类对象
3. 接口不是类,同时接口是特殊的抽象类。因此无法实例化对象。
4. 接口中存在未完成的方法,就算是有对象,也得报错的。带有泛型的接口使用需要依赖于实现类完成。这里有两种方式。
package com.llq;
public interface Demo4 <T>{
T getTest(T t);
}
class Demo5<T> implements Demo4<T>{
/**
* 自由方式
* 实现类使用和接口相同的泛型,泛型对应具体数据类型在创建
* 当前类对象时明确
* @author Anonymous
* @param
*/
@Override
public T getTest(T t) {
return t;
}
}
class Demo6<T> implements Demo4<String> {
/**
* 实现类在遵从带有自定义泛型的接口时,接口中泛型的具体数据
类型已经确认
* 实现类完成的对应方法就OK
*
*/
@Override
public String getTest(String t) {
// TODO Auto-generated method stub
return null;
}
}
【总结】接口中的泛型使用视开发情况而定。
? 是泛型的通配符
class Animal {}
class Dog extends Animal{}
class Cat extends Animal{}
class Node<T> {}
class Flower{}
public class Test {
public static void main(String[] args) {
Node<? extends Animal> an = new Node<Dog>();
}
}
【总结】泛型的上界的约束存在于父子类之中,同时在实例化对象的时候确定泛型的种类是在于创建类对象的时候,同时如果extends后指出类型的时候除了此类型之外还满足于存入该类的引用类型以及指定类型的子类或者间接子类。