嵌入式之路,贵在日常点滴
---阿杰在线送代码
目录
一、泛型简介
二、泛型类及特点
1、泛型的类型参数可以是泛型类
2、泛型类可以同时设置多个类型参数
3、泛型类可以继承泛型类
4、泛型类可以实现泛型接口
三、限制泛型可用类型
四、类型通配的方式
类型通配声明 例子
类型通配的方式
五、泛型方法
什么时候使用泛型方法,而不是泛型类呢?
问题:如果我们需要产生多个对象,每个对象的逻辑完全一样,只要对象内的成员变量的类型不同,那我们如何去做?
缺点:这种方式会导致类的膨胀,重用型太差。
class Cls1
{
int a;
public Cls1(int a){
this.a = a;
}
public int getData(){
return a;
}
}
class Cls2
{
String a;
public Cls2(String a){
this.a = a;
}
public String getData(){
return a;
}
}
public class Test {
public static void main(String[] args) {
Cls1 cls1 = new Cls1(10);
System.out.println(cls1.getData());
Cls2 cls2 = new Cls2("ajie");
System.out.println(cls2.getData());
}
}
运行结果:
10
ajie
缺点,编译的时候正常,但运行的时候可能会异常。 (因为其类型比较模糊,有时候做了错误得类型转换就会导致运行程序时崩溃,编译没有错误)
鼠标定位到数据类型,右键 选择 Type Hierarchy
观察可以看出Object是所有数据类型的父类
class Cls1
{
Object a;
public Cls1(Object a){
this.a = a;
}
public Object getData(){
return a;
}
}
public class Test {
public static void main(String[] args) {
Cls1 cls1 = new Cls1(10);
System.out.println(cls1.getData());
Cls1 cls2 = new Cls1("ajie");
System.out.println(cls2.getData());
}
}
为解决此问题,我们引入 泛型
class Cls1
{
T a;
public Cls1(T a){
this.a = a;
}
public T getData(){
return a;
}
}
public class Test {
public static void main(String[] args) {
Cls1 cls1 = new Cls1(10);
System.out.println(cls1.getData());
Cls1 cls2 = new Cls1("ajie");
System.out.println(cls2.getData());
}
}
运行结果:
10
ajie
myeclipse工程环境出错:Set project compiler compliance settings to '1.5'
解决方案
class Cls1
{
T a;
public Cls1(T a){
this.a = a;
}
public T getData(){
return a;
}
}
public class Test {
public static void main(String[] args) {
Cls1> cls1 = new Cls1>(new Cls1(10));
System.out.println(cls1.getData().getData());
}
}
运行结果:
10
class Cls2
{
T a;
T2 b;
public Cls2(T a,T2 b){
this.a = a;
this.b = b;
}
public T getData(){
return a;
}
public T2 getData2(){
return b;
}
}
public class Test {
public static void main(String[] args) {
Cls2 cls3 = new Cls2(100,"ajie");
System.out.println(cls3.getData());
System.out.println(cls3.getData2());
System.out.println(cls3.getData()+cls3.getData2());
Cls2 cls4 = new Cls2(100,10);
System.out.println(cls4.getData()+cls4.getData2());//注意,在以前我们这里用到的+都是链接作用
//在这里+可以作为加法使用
int sum = 0;
sum = cls4.getData()+cls4.getData2();
System.out.println(sum);
}
}
运行结果:
100
ajie
100ajie
110
110
abstract class Cls1
{
T a;
public Cls1(T a){
this.a = a;
}
public T getData(){
return a;
}
abstract void printInfo();
}
class Cls2 extends Cls1
{
T2 b;
public Cls2(T a,T2 b){
super(a);//调用了父类的构造方法,这个语句必须放在子类构造方法的第一句
this.b = b;
}
public T2 getData2(){
return b;
}
@Override
void printInfo() {
// TODO Auto-generated method stub
System.out.println("print");
}
}
public class Test {
public static void main(String[] args) {
Cls2 cls = new Cls2(10,"ajie");
System.out.println(cls.getData());
System.out.println(cls.getData2());
cls.printInfo();
}
}
运行结果:
10
ajie
abstract class Cls1
{
T a;
public Cls1(T a){
this.a = a;
}
public T getData(){
return a;
}
abstract void printInfo();
}
interface Cls3
{
abstract void printInfoCls3(T t);
}
class Cls2 extends Cls1 implements Cls3
{//如果Cls2的T和Cls3T是同名,则在下面主函数使用时,Cls3的类型遵循Cls2,否则会报错
//即使不同名,也会报错 问题如何解决 在下面展示
T2 b;
public Cls2(T a,T2 b){
super(a);//调用了父类的构造方法,这个语句必须放在子类构造方法的第一句
this.b = b;
}
public T2 getData2(){
return b;
}
@Override
void printInfo() {
// TODO Auto-generated method stub
System.out.println("print");
}
@Override
public void printInfoCls3(T t) {
// TODO Auto-generated method stub
System.out.println(t);
}
}
public class Test {
public static void main(String[] args) {
Cls2 cls = new Cls2(10,"ajie");
System.out.println(cls.getData());
System.out.println(cls.getData2());
cls.printInfo();
cls.printInfoCls3(100);
}
}
运行结果:
10
ajie
100
如何解决 如果Cls2的T和Cls3的T是同名,则在下面主函数使用时,Cls3的T类型遵循Cls2,否则会报错 问题。即使不同名,也会报错
abstract class Cls1
{
T a;
public Cls1(T a){
this.a = a;
}
public T getData(){
return a;
}
abstract void printInfo();
}
interface Cls3
{
abstract void printInfoCls3(T3 t);
}
class Cls2 extends Cls1 implements Cls3
{//如果Cls2的T和Cls3T是同名,则在下面主函数使用时,Cls3的类型遵循Cls2,否则会报错
T2 b;
public Cls2(T a,T2 b){
super(a);//调用了父类的构造方法,这个语句必须放在子类构造方法的第一句
this.b = b;
}
public T2 getData2(){
return b;
}
@Override
void printInfo() {
// TODO Auto-generated method stub
System.out.println("print");
}
@Override
public void printInfoCls3(T3 t) {
// TODO Auto-generated method stub
System.out.println(t);
}
}
public class Test {
public static void main(String[] args) {
Cls2 cls = new Cls2(10,"ajie");
System.out.println(cls.getData());
System.out.println(cls.getData2());
cls.printInfo();
cls.printInfoCls3("ajie");
}
}
在定义泛型类别时,默认在实例化泛型类的时候可以使用任何类型,但是如果想要限制使用泛型类型时,只能用某个特定类型或者是其子类型才能实例化该类型时,可以在定义类型时,使用extends关键字指定这个类型必须是继承某个类,或者实现某个接口。
当没有指定泛型继承的类型或接口时,默认使用extends Object。所以默认情况下任何类型都可以作为参数传入。
//默认情况下,以下两种情况是一样的
class Cls1
{
T a;
public Cls1(T a){
this.a = a;
}
public T getData(){
return a;
}
}
class Cls1
{
T a;
public Cls1(T a){
this.a = a;
}
public T getData(){
return a;
}
}
//使用extends关键字指定这个类型
abstract class Cls1
{
T a;
public Cls1(T a){
this.a = a;
}
public T getData(){
return a;
}
abstract void printInfo();
}
interface Cls3
{
abstract void printInfoCls3(T3 t);
}
class Cls2 extends Cls1 implements Cls3
{
T2 b;
public Cls2(T a,T2 b){
super(a);//调用了父类的构造方法,这个语句必须放在子类构造方法的第一句
this.b = b;
}
public T2 getData2(){
return b;
}
@Override
void printInfo() {
// TODO Auto-generated method stub
System.out.println("print");
}
@Override
public void printInfoCls3(T3 t) {
// TODO Auto-generated method stub
System.out.println(t);
}
}
//使用extends关键字指定这个类型必须是继承某个类
class Animal
{
}
class Dog extends Animal
{
}
abstract class Cls1
{
T a;
public Cls1(T a){
this.a = a;
}
public T getData(){
return a;
}
abstract void printInfo();
}
interface Cls3
{
abstract void printInfoCls3(T3 t);
}
class Cls2 extends Cls1 implements Cls3
{
T2 b;
public Cls2(T a,T2 b){
super(a);//调用了父类的构造方法,这个语句必须放在子类构造方法的第一句
this.b = b;
}
public T2 getData2(){
return b;
}
@Override
void printInfo() {
// TODO Auto-generated method stub
System.out.println("print");
}
@Override
public void printInfoCls3(T3 t) {
// TODO Auto-generated method stub
System.out.println(t);
}
}
//使用extends关键字指定这个类型必须是继承某个类,或者实现某个接口。
interface Move
{
abstract void test();
}
class A implements Move//正常继承实现接口的方法使用的是implements
{
public void test(){
}
}
abstract class Cls1//但是在泛型这里需要使用extends限定
{
T a;
public Cls1(T a){
this.a = a;
}
public T getData(){
return a;
}
abstract void printInfo();
}
interface Cls3
{
abstract void printInfoCls3(T3 t);
}
class Cls2 extends Cls1 implements Cls3
{
T2 b;
public Cls2(T a,T2 b){
super(a);//调用了父类的构造方法,这个语句必须放在子类构造方法的第一句
this.b = b;
}
public T2 getData2(){
return b;
}
@Override
void printInfo() {
// TODO Auto-generated method stub
System.out.println("print");
}
@Override
public void printInfoCls3(T3 t) {
// TODO Auto-generated method stub
System.out.println(t);
}
}
以上这些实际编程时很少用,现在是用来科普我们的认知,看到要认识。
后续编程安卓可能会用到。
同一泛型类,如果实例化时给定的实际类型不同,则这些实例的类型是不兼容的,不能相互赋值。
Cls1 c1 = new Cls1();
Cls1 c2 = new Cls1();
c1 = c2;//发生编译错误
Cls1
泛型类实例之间的不兼容性会带来使用的不便。我们可以使用泛型通配符(?)声明泛型类的变量就可以解决这个问题。
class Animal
{
}
class Dog extends Animal
{
}
class Cls1
{
T a;
public Cls1(T a){
this.a = a;
}
public T getData(){
return a;
}
}
public class Test {
public static void main(String[] args) {
Cls1 c1 = new Cls1(10);
Cls1 c2 = new Cls1(10.0);
Cls1> c3;
c3 = c1;
c3 = c2;
}
}
class Animal
{
}
class Dog extends Animal
{
}
class Cls1
{
T a;
public Cls1(T a){
this.a = a;
}
public T getData(){
return a;
}
}
public class Test {
public static void main(String[] args) {
Cls1 c1 = new Cls1(new Dog());
Cls1 extends Animal> c2;
c2 = c1;
}
}
class Animal
{
}
class Dog extends Animal
{
}
class Cls1
{
T a;
public Cls1(T a){
this.a = a;
}
public T getData(){
return a;
}
}
public class Test {
public static void main(String[] args) {
Cls1 c1 = new Cls1(new Dog());
Cls1 super Dog> c2;
//Cls1 c1 = new Cls1(new Dog());
//Cls1 super Dog> c2;
c2 = c1;
}
}
访问修饰符 <泛型列表> 返回类型 方法名(参数列表){
实现代码
}
提示: 是否拥有泛型方法与其所在的类是否泛型没有关系。要定义泛型方法,只需将泛型参数列表置于返回值前。
class A
{
public void printInfo(T t){
System.out.println(t);
}
}
class B
{
public void printInfo(T t){
System.out.println(t);
}
}
public class Test {
public static void main(String[] args) {
A a = new A();
a.printInfo("ajie");//此泛型中的方法参数类型被类的泛型类型限制住
B b = new B();
b.printInfo("ajiezaixian");//泛型方法不应该被类的泛型类型限制住
b.printInfo(1234);
b.printInfo(0.5);
}
}
运行结果:
ajie
ajiezaixian
1234
0.5
class A
{
public void printInfo(T t){
System.out.println(t);
}
}
class B
{
//泛型方法
public void printInfo(T t){
System.out.println(t);
}
//泛型方法的重载
public void printInfo(T t,T2 t2){
System.out.println(t);
System.out.println(t2);
//System.out.println(t+t2);会报错 只有实例化确定类型后才让加 跟我们之前遇到的要区分开
}
}
public class Test {
public static void main(String[] args) {
A a = new A();
a.printInfo("ajie");//此泛型中的方法参数类型被类的泛型类型限制住
B b = new B();
b.printInfo("ajiezaixian");//泛型方法不应该被类的泛型类型限制住
b.printInfo(1234);
b.printInfo(0.5);//比方法重载好用多了
b.printInfo("ajie", "这是泛型方法的重载");
}
}
运行结果
ajie
ajiezaixian
1234
0.5
ajie
这是泛型方法的重载
添加类型约束只作用于一个方法的多个参数之间、而不涉及到类中的其他方法时。
施加类型约束的方法为静态方法,只能将其定义为泛型方法,因为静态方法不能使用其所在类的类型参数。
class Animal
{
public void eat(){
System.out.println("动物吃");
}
}
class Dog extends Animal
{
public void eat(){
System.out.println("啃骨头");
}
}
class Cat extends Animal
{
public void eat(){
System.out.println("吃鱼肉");
}
}
class B
{
//泛型方法
public void printInfo(T t){
System.out.println(t);
}
public static void printInfo(T t){
t.eat();
}
}
public class Test {
public static void main(String[] args) {
B b = new B();
b.printInfo(new Dog());
b.printInfo(new Cat());
b.printInfo(new Animal());
B.printInfo(new Dog());
}
}
运行结果:
啃骨头
吃鱼肉
动物吃
啃骨头