一、泛型基本概念
1、什麼是泛型
泛型就是參數化類型,使用廣泛的類型;聲明時使用泛型,使用時指定具體類型
2、泛型常見的字母及對應含義
T :Type表示類型
K V:分別表示鍵值對中的key和value
E:表示Element元素類型
? :表示不確定的類型
3、泛型的優點:省心、安全
(1)安全:在編譯時檢查類型安全
(2)省心:所有的強制轉換都是自動和隱式的,同一套代碼可以用於多種數據類型,提高代碼的重用率
public class Student<T1,T2> {
private T1 name;
private T2 age;
public T1 getName() {
return name;
}
public void setName(T1 name) {
this.name = name;
}
public T2 getAge() {
return age;
}
public void setAge(T2 age) {
this.age = age;
}
public static void main(String[] args) {
//使用時指定類型
Student<String,Integer> stu = new Student<String,Integer>();
//安全:類型檢查
stu.setName("張三");
//stu.setAge("20"); 類型檢查報錯
//省心:類型轉換
String str = stu.getName();
}
}
4、泛型類
泛型類:定義類時使用泛型,使用時確定類型
注意事項:
1、泛型聲明時不能使用在靜態屬性和靜態方法上(因爲靜態方法屬性在編譯時確定類型)
2、泛型字母只能使用引用類型,不能使用基本類型
package cn.cjy.generics;
/**
* 泛型類:定義類時使用泛型,使用時確定類型
* 1、泛型聲明時不能使用在靜態屬性和靜態方法上(因爲靜態方法屬性在編譯時確定類型)
* 2、泛型字母只能使用引用類型,不能使用基本類型
*/
public class Student<T1,T2> {
private T1 name;
private T2 age;
public T1 getName() {
return name;
}
public void setName(T1 name) {
this.name = name;
}
public T2 getAge() {
return age;
}
public void setAge(T2 age) {
this.age = age;
}
public static void main(String[] args) {
//使用時指定類型
Student<String,Integer> stu = new Student<String,Integer>();
//安全:類型檢查
stu.setName("張三");
//stu.setAge("20"); 類型檢查報錯
//省心:類型轉換
String str = stu.getName();
}
}
5、泛型接口
接口中,泛型字母只能使用在方法中,不能使用在全局常量中
/**
* 泛型接口:接口中,泛型字母只能使用在方法中,不能使用在全局常量中
*
*/
public interface Comparator<T> {
void comparator(T t);
}
6、泛型方法
泛型方法<>:定義在返回類型前面
1、只能訪問對象信息,不能修改對象信息
2、extends <=:表示T只能是Closeable及其子類 (…表示可變參數)
package cn.cjy.generics;
import java.io.Closeable;
import java.io.IOException;
/**
* 泛型方法<>:定義在返回類型前面
* 1、只能訪問對象信息,不能修改對象信息
* 2、extends <=:表示T只能是Closeable及其子類 (...表示可變參數)
*
*/
public class MethodTest {
public static void main(String[] args) {
test("測試"); // T-->String
}
//泛型方法
public static <T> void test(T t){
System.out.println(t);
}
//extends <=:表示T只能是Closeable及其子類 (...表示可變參數)
public static <T extends Closeable> void test(T... t){
for(T temp:t){
try {
if(null!=temp){
temp.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
二、泛型的使用
1、父類爲泛型類的繼承
(1)屬性類型:在父類中屬性類型隨父類定,在子類中屬性類型隨子類定
(2)重寫方法類型:隨父類而定
(3)泛型擦除:要麼子類、父類同時擦除,要麼子類>=父類類型,不能子類擦除父類泛型
a、繼承或實現不指定類型
b、使用時不指定類型,統一Object類型對待,但是不完全等同於Object,編譯時不會類型檢查
package cn.cjy.generics;
/**
* 父類爲泛型類
* 1、屬性
* 2、方法
*泛型擦除:要麼子類、父類同時擦除,要麼子類>=父類類型,不能子類擦除父類泛型
*1、屬性類型:在父類中屬性類型隨父類定,在子類中屬性類型隨子類定
*2、重寫方法類型:隨父類而定
*/
public abstract class Father<T,T1> {
T name;
public abstract void test(T t);
}
/**
* 子類聲明時指定具體類型
* 1、屬性類型爲具體類型
* 2、方法類型爲具體類型
*/
class child1 extends Father<String,Integer>{
String str;
@Override
public void test(String t) {
}
}
/**
* 子類爲泛型類,類型在使用時確定
* 子類的泛型個數大於等於父類,父類有的子類都要要
*
*/
class child2<T,T1,T2> extends Father<T,T1>{
T1 t1;
@Override
public void test(T t) {
}
}
/**
* 泛型的擦除:子類爲泛型類,父類不指定類型,重寫方法使用Object替換泛型
*
*/
class child3<T,T1> extends Father{
T1 t1;
@Override
public void test(Object t) {
}
}
/**
* 子類與父類泛型同時擦除:子類爲泛型類,父類不指定類型,重寫方法使用Object替換泛型
*
*/
class child4 extends Father{
String name;
@Override
public void test(Object t) {
}
}
/**
* 子類擦除,父類使用泛型:錯誤的使用
*
class child4 extends Father<T,T1>{
String name;
@Override
public void test(Object t) {
}
}
*/
2、泛型接口的實現
package cn.cjy.generics;
/**
* 泛型接口
* 重寫方法類型隨父類而定
*
*/
public interface Comparator01<T> {
void compare(T t);
}
//聲明子類指定具體類型
class test implements Comparator01<String>{
@Override
public void compare(String t) {
}
}
//父類子類同事擦除
class test1 implements Comparator01{
@Override
public void compare(Object t) {
}
}
//父類擦除,子類泛型
class test2<T> implements Comparator01{
@Override
public void compare(Object t) {
}
}
//子類泛型>=父類泛型
class test3<T,T1> implements Comparator01<T>{
@Override
public void compare(T t) {
}
}
3、泛型實現多態效果:使用通配符?
(1)多態,泛型沒有多態!
package cn.cjy.generics;
/**
* 多態
* 1、形參多態
* 3、返回類型多態
*
*/
public class Fruit {
}
class Apple extends Fruit{
}
class Test{
public static void main(String[] args) {
Fruit f = new Apple();
}
//形參使用多態
public static void test1(Fruit t){
}
//返回類型使用多態
public static Fruit test2(){
return new Apple();
}
}
(2)泛型使用通配符?
a、類型不定,使用時確定類型
b、可以用在聲明類型、聲明方法參數上,不能用在聲明類上或者使用時
c、可以接收泛型的任意類型,只能接收和輸出,不能修改
d、? extends 泛型上限 <= 指定類型爲自身或子類
e、? super 泛型下限 >= 指定類型爲自身或父類
package cn.cjy.generics;
/**
* 通配符?的使用:
* 1、類型不定,使用時確定類型
* 2、可以用在聲明類型、聲明方法參數上,不能用在聲明類上或者使用時
* 3、可以接收泛型的任意類型,只能接收和輸出,不能修改
* 4、? extends 泛型上限 <=
* 5、? super 泛型下限 >=
*
*/
public class StudentTest<T> {
T score;
public static void main(String[] args) {
StudentTest<?> stu = new StudentTest<String>();
test(new StudentTest<String>());
test1(new StudentTest<Apple>()); //類似與多態的效果
//test2(new StudentTest<Apple>()); 報錯,泛型沒有多態
test3(new StudentTest<Object>());
}
public static void test(StudentTest<?> stu){
}
public static void test1(StudentTest<? extends Fruit> stu){
}
public static void test2(StudentTest<Fruit> stu){
}
public static void test3(StudentTest<? super Fruit> stu){
}
}
4、泛型嵌套
package cn.cjy.generics;
/**
* 泛型嵌套
*
*/
public class TestNest<T> {
T stu;
public static void main(String[] args) {
//泛型的嵌套
TestNest<StudentTest<String>> test = new TestNest<StudentTest<String>>();
//從外到內拆封
test.stu = new StudentTest<String>();
StudentTest<String> stu = test.stu;
String score = stu.score;
System.out.println(score);
}
}
三、注意事項
1、泛型沒有多態
2、沒有泛型數組,聲明可以使用,不能創建泛型數組
四、instanceof用法總結
instanceof用於測試左邊的對象是否是右邊的類或其子類的實例,返回 boolean 的數據類型
package cn.cjy.generics;
/**
* instanceof的用法
*/
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
public class TestInstanceof {
public static void main(String[] args) {
List list = new ArrayList();
test(list);
}
public static void test(Object o) {
if (o instanceof Vector){
System.out.println("對象是 Vector類的實例");
}
else if (o instanceof ArrayList){
System.out.println("對象是ArrayList類的實例");
}
else{
System.out.println("對象是 " + o.getClass() + " 類的實例");
}
}
}