Java基础(2) 之面向对象

文章目录

      • Java基础(2) 之面向对象
        • 1.对象
        • 2.类
          • 类的注意事项
        • 3.this关键字
        • 4.构造器
          • 注意
        • 5.封装性
        • 6.实体JavaBean
          • 实体类
        • 7.成员变量和局部变量的区别
        • 8.static
          • static修饰成员变量
          • static修饰成员方法
          • static的注意事项
          • 工具类
          • 单例设计模式
        • 9.代码块
          • 静态代码块
          • 实例代码块
        • 10.继承
          • 权限修饰符
          • 单继承与object
          • 方法重写
          • 子类访问成员的特点
          • 子类访问构造器的特点
            • 访问自己类的构造器
        • 11.多态
          • 多态的类型转换
        • 12.final关键字
        • 13.抽象类
          • 模板方法模式
        • 14.接口
          • 好处:
          • 接口也能继承
        • 15.内部类
          • 成员内部类
          • 静态内部类
          • 局部内部类
          • 匿名内部类
        • 16.枚举
        • 17.泛型
          • 泛型类
          • 自定义泛型类
          • 自定义泛型接口
          • 泛型方法
          • 泛型限定
          • 泛型擦除

Java基础(2) 之面向对象

  • 面向对象编程有什么好处?

  • 面向对象的开发更符合人类的思维习惯,让编程变得更加简单、更加直观。

1.对象
  • 对象实质上是一种特殊的数据结构。这种结构怎么理解呢?

    你可以把对象理解成一张表格,表当中记录的数据,就是对象拥有的数据

    一句话总结,对象其实就是一张数据表,表当中记录什么数据,对象就处理什么数据。

  • Student s1 = new Student();这句话中的原理如下

    • Student s1表示的是在栈内存中,创建了一个Student类型的变量,变量名为s1

    • new Student()会在堆内存中创建一个对象,而对象中包含学生的属性名和属性值

      同时系统会为这个Student对象分配一个地址值0x4f3f5b24

    • 接着把对象的地址赋值给栈内存中的变量s1,通过s1记录的地址就可以找到这个对象

    • 当执行s1.name=“播妞”时,其实就是通过s1找到对象的地址,再通过对象找到对象的name属性,再给对象的name属性赋值为播妞;

2.类

用什么来设计这张表呢?就是类(class),类可以理解成对象的设计图,或者对象的模板。设计图中规定有哪些数据,对象中就只能有哪些数据。

  • 对象可以理解成一张数据表,而数据表中可以有哪些数据,是有类来设计的。
类的注意事项

在这里插入图片描述

3.this关键字
  • 哪一个对象调用方法,方法中的this就是哪一个对象

通过this在方法中可以访问本类对象的成员变量

4.构造器

构造器就是用来创建对象的。可以在创建对象时给对象的属性做一些初始化操作

  • 构造器其实是一种特殊的方法,但是这个方法没有返回值类型,方法名必须和类名相同。

  • 在创建对象时,会调用构造器。

  • 也就是说 new Student()就是在执行构造器,当构造器执行完了,也就意味着对象创建成功。

  • new 对象就是在执行构造方法

注意
  • 1.在设计一个类时,如果不写构造器,Java会自动生成一个无参数构造器。
  • 2.一旦定义了有参数构造器,Java就不再提供空参数构造器,此时建议自己加一个无参数构造器。
5.封装性

所谓封装,就是用类设计对象处理某一个事物的数据时,应该把要处理的数据,以及处理数据的方法,都设计到一个对象中去。

  • 封装的设计规范:

    • 合理隐藏、合理暴露
  • 体现:

    • private修饰的变量或者方法,只能在本类中被访问。

    • private double score; 就相当于把score变量封装在了Student对象的内部,且不对外暴露,你想要在其他类中访问score这个变量就,就不能直接访问了;

      如果你想给Student对象的score属性赋值,得调用对外暴露的方法setScore(int score),在这个方法中可以对调用者传递过来的数据进行一些控制,更加安全。

      在这里插入图片描述

6.实体JavaBean
实体类
  • 实体类中除了有给对象存、取值的方法就没有提供其他方法了。所以实体类仅仅只是用来封装数据用的。

实体类就是一种特殊的类,它需要满足下面的要求:

在这里插入图片描述

  • 实体类仅仅只用来封装数据,而对数据的处理交给其他类来完成,以实现数据和数据业务处理相分离
7.成员变量和局部变量的区别

在这里插入图片描述

面向对象的核心点就是封装,将数据和数据的处理方式,都封装到对象中; 至于对象要封装哪些数据?对数据进行怎样的处理? 需要通过类来设计。

需要注意的是,不同的人,对同一个对象进行设计,对象封装那些数据,提供哪些方法,可能会有所不同;只要能够完成需求,符合设计规范,都是合理的设计。

8.static

static读作静态,可以用来修饰成员变量,也能修饰成员方法。

static修饰成员变量
  • 实际开发中,如果某个数据只需要一份,且希望能够被共享(访问、修改),则该数据可以定义成类变量来记住。

Java中的成员变量按照有无static修饰分为两种:类变量、实例变量。它们的区别如下:

在这里插入图片描述

静态变量是属于类的,只需要通过类名就可以调用:类名.静态变量

实例变量是属于对象的,需要通过对象才能调用:对象.实例变量

static修饰成员方法

成员方法根据有无static也分为两类:类方法、实例方法

在这里插入图片描述

有static修饰的方法,是属于类的,称为类方法;调用时直接用类名调用即可。

无static修饰的方法,是属于对象的,称为实例方法;调用时,需要使用对象调用。

static的注意事项

在这里插入图片描述

工具类

如果一个类中的方法全都是静态的,那么这个类中的方法就全都可以被类名直接调用,由于调用起来非常方便,就像一个工具

  • 工具类里的方法全都是静态的,推荐用类名调用为了防止使用者用对象调用。我们可以把工具类的构造方法私有化
public class MyUtils{//私有化构造方法:这样别人就不能使用构造方法new对象了private MyUtils(){}//类方法public static String createCode(int n){...}
}
  • 示例:生成验证码的工具类

  • public class MyUtils{public static String createCode(int n){//1.定义一个字符串,用来记录产生的验证码String code = "";//2.验证码是由所有的大写字母、小写字母或者数字字符组成//这里先把所有的字符写成一个字符串,一会从字符串中随机找字符String data = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKMNOPQRSTUVWXYZ";//3.循环n次,产生n个索引,再通过索引获取字符Random r = new Random();for(int i=0; i<n; i++){int index = r.nextInt(data.length());char ch = data.charAt(index);//4.把获取到的字符,拼接到code验证码字符串上。code+=ch;}//最后返回code,code的值就是验证码return code;}
    }
    
单例设计模式

让类对外只能产生一个对象;如任务管理器对象

  • 把类的构造器私有。

  • 定义一个类变量记住类的一个对象。

  • 定义一个类方法,返回对象。

  • 在这里插入图片描述

  • 懒汉式(拿对象时,才开始创建对象。)

    • 把类的构造器私有。

      定义一个类变量用于存储对象。

      提供一个类方法,保证返回的是同一个对象。

      在这里插入图片描述

9.代码块

代码块根据有无static修饰分为两种:静态代码块实例代码块

静态代码块

在这里插入图片描述

静态代码块不需要创建对象就能够执行

静态代码块,随着类的加载而执行,而且只执行一次

实例代码块
  • 实例代码块的作用和构造器的作用是一样的,用来给对象初始化值;而且每次创建对象之前都会先执行实例代码块.

    在这里插入图片描述

10.继承

在这里插入图片描述

子类对象实际上是由子、父类两张设计图共同创建出来的。

其实像这种两个类中有相同代码时,没必要重复写。

我们可以把重复的代码提取出来,作为父类,然后让其他类继承父类就可以了,这样可以提高代码的复用性。

权限修饰符

权限修饰符是用来限制类的成员(成员变量、成员方法、构造器…)能够被访问的范围。

在这里插入图片描述

单继承与object
  • Java语言只支持单继承,不支持多继承,但是可以多层继承

  • Java是单继承的:一个类只能继承一个直接父类;

  • Object类是Java中所有类的祖宗

方法重写

当子类觉得父类方法不好用,或者无法满足父类需求时,子类可以重写一个方法名称、参数列表一样的方法,去覆盖父类的这个方法,这就是方法重写。

  • 重写后,方法的访问遵循就近原则

    • 1.重写的方法上面,可以加一个注解@Override,用于标注这个方法是复写的父类方法

    • 2.子类复写父类方法时,访问权限必须大于或者等于父类方法的权限

      • public > protected > 缺省

      1. 重写的方法返回值类型,必须与被重写的方法返回值类型一样,或者范围更小
      1. 私有方法、静态方法不能被重写,如果重写会报错。
  • 示例:

    • public class A {public void print1(){System.out.println("111");}public void print2(int a, int b){System.out.println("111111");}
      }
      
    • public class B extends A{// 方法重写@Override // 安全,可读性好public void print1(){System.out.println("666");}// 方法重写@Overridepublic void print2(int a, int b){System.out.println("666666");}
      }
      
    • 尽量做到声明不变,重新实现

应用场景之一就是:子类重写Object的toString()方法,以便返回对象的内容。

子类访问成员的特点

继承至少涉及到两个类,而每一个类中都可能有各自的成员(成员变量、成员方法),就有可能出现子类和父类有相同成员的情况,那么在子类中访问其他成员有什么特点呢?

  • 在子类中访问其他成员(成员变量、成员方法),是依据就近原则的

  • 如果子类和父类出现同名变量或者方法,优先使用子类的;此时如果一定要在子类中使用父类的成员,可以加this或者super进行区分。

子类访问构造器的特点

子类中访问构造器的语法规则

  • 子类全部构造器,都会先调用父类构造器,再执行自己。

在这里插入图片描述

  • 如果不想使用默认的super()方式调用父类构造器,还可以手动使用super(参数)调用父类有参数构造器。

在这里插入图片描述

访问自己类的构造器

this(): 调用本类的空参数构造器
this(参数): 调用本类有参数的构造器

如下图:

在这里插入图片描述

  • 注意:this和super访问构造方法,只能用到构造方法的第一句,否则会报错。

访问本类成员:
this.成员变量 //访问本类成员变量
this.成员方法 //调用本类成员方法
this() //调用本类空参数构造器
this(参数) //调用本类有参数构造器

访问父类成员:
super.成员变量 //访问父类成员变量
super.成员方法 //调用父类成员方法
super() //调用父类空参数构造器
super(参数) //调用父类有参数构造器

11.多态

什么是多态?

多态是在继承、实现情况下的一种现象,表现为:对象多态、行为多态。

在这里插入图片描述

在多态形式下,右边的代码是解耦合的,更便于扩展和维护。

定义方法时,使用父类类型作为形参,可以接收一切子类对象,扩展行更强,更便利。

public class Test2 {public static void main(String[] args) {// 目标:掌握使用多态的好处Teacher t = new Teacher();go(t);Student s = new Student();go(s);}//参数People p既可以接收Student对象,也能接收Teacher对象。public static void go(People p){System.out.println("开始------------------------");p.run();System.out.println("结束------------------------");}
}
多态的类型转换

多态形式下,不能调用子类特有的方法,比如在Teacher类中多了一个teach方法,在Student类中多了一个study方法,这两个方法在多态形式下是不能直接调用的。

在这里插入图片描述

  • 但是转型后是可以调用的

在这里插入图片描述

  • 因此我们最终记住一句话:原本是什么类型,才能还原成什么类型
12.final关键字

面向对象编程中偶尔会用到的一个关键字叫final,也是为后面学习抽象类接口做准备的

  • final修饰:该类称为最终类,特点是不能被继承

    • 在这里插入图片描述

  • final修饰方法:该方法称之为最终方法,特点是不能被重写

  • final修饰变量:该变量只能被赋值一次

    • 在这里插入图片描述

      在这里插入图片描述

      在这里插入图片描述

  • static final 修饰的成员变量,称之为常量

  • 在程序编译后,常量会“宏替换”,出现常量的地方,全都会被替换为其记住的字面量

13.抽象类

在Java中有一个关键字叫abstract,它就是抽象的意思,它可以修饰也可以修饰方法。

  • 被abstract修饰的类,就是抽象类
  • 被abstract修饰的方法,就是抽象方法(不允许有方法体
//abstract修饰类,这个类就是抽象类
public abstract class A{//abstract修饰方法,这个方法就是抽象方法public abstract void test();
}
  • 类的成员(成员变量、成员方法、构造器),类的成员都可以有。
  • 抽象类是不能创建对象的,如果抽象类的对象就会报错

抽象类虽然不能创建对象,但是它可以作为父类让子类继承。而且子类继承父类必须重写父类的所有抽象方法。

子类继承父类如果不复写父类的抽象方法,要想不出错,这个子类也必须是抽象类

  • 好处

    • 1.用抽象类可以把父类中相同的代码,包括方法声明都抽取到父类,这样能更好的支持多态,一提高代码的灵活性。

      2.反过来用,我们不知道系统未来具体的业务实现时,我们可以先定义抽象类,将来让子类去实现,以方便系统的扩展。

模板方法模式

模板方法模式解决了多个子类中有相同代码的问题

第1步:定义一个抽象类,把子类中相同的代码写成一个模板方法。
第2步:把模板方法中不能确定的代码写成抽象方法,并在模板方法中调用。
第3步:子类继承抽象类,只需要父类抽象方法就可以了。

  • 模板方法模式主要解决方法中存在重复代码的问题

  • 在这里插入图片描述

  • 我们可以写一个抽象类C类,在C类中写一个doSing()的抽象方法。再写一个sing()方法

    先设计模板方法:

    // 模板方法设计模式
    public abstract class C {// 模板方法public final void sing(){System.out.println("唱一首你喜欢的歌:");doSing();System.out.println("唱完了!");}public abstract void doSing();
    }
    
  • 写一个A类和B类继承C类,复写doSing()方法,代码如下

    • public class A extends C{@Overridepublic void doSing() {System.out.println("我是一只小小小小鸟,想要飞就能飞的高~~~");}
      }
      
      public class B extends C{@Overridepublic void doSing() {System.out.println("我们一起学猫叫,喵喵喵喵喵喵喵~~");}
      }
      
14.接口
  • 总结为一句话,就是接口实现之后我就可以用接口来接收所有实现了接口的对象,因为所有的这些对象都重写了接口的方法,充分利用了多态。

比抽象类抽象得更加彻底的一种特殊结构

  • Java提供了一个关键字interface,用这个关键字来定义接口这种特殊结构。格式如下:

  • public interface 接口名{//成员变量(常量)//成员方法(抽象方法)
    }
    

    定义好接口之后,是不能创建对象的

  • 所以说接口有什么用?

    • 接口是用来被类实现(implements)的,我们称之为实现类。
    • 一个类是可以实现多个接口的(接口可以理解成干爹),类实现接口必须重写所有接口的全部抽象方法,否则这个类也必须是抽象类
    • 比如,定义一个B接口,里面有两个方法testb1(),testb2()

    • public interface B {void testb1();void testb2();
      }
      
    • 再定义一个C接口,里面有两个方法testc1(), testc2()

    • public interface C {void testc1();void testc2();
      }
      
    • 再写一个实现类D,同时实现B接口和C接口,此时就需要复写四个方法

    • // 实现类
      public class D implements B, C{@Overridepublic void testb1() {}@Overridepublic void testb2() {}@Overridepublic void testc1() {}@Overridepublic void testc2() {}
      }
      
好处:
  • 弥补了类单继承的不足,一个类同时可以实现多个接口。

  • 让程序可以面向接口编程,这样程序员可以灵活方便的切换各种业务实现。

  • class Student{}interface Driver{void drive();
    }interface Singer{void sing();
    }//A类是Student的子类,同时也实现了Dirver接口和Singer接口
    class A extends Student implements Driver, Singer{@Overridepublic void drive() {}@Overridepublic void sing() {}
    }public class Test {public static void main(String[] args) {//想唱歌的时候,A类对象就表现为Singer类型Singer s = new A();s.sing();//想开车的时候,A类对象就表现为Driver类型Driver d = new A();d.drive();}
    }
    
  • 接口弥补了单继承的不足,同时可以轻松实现在多种业务场景之间的切换。

  • 在JDK8版本以后接口中能够定义的成员也做了一些更新

    • public interface A {/*** 1、默认方法:必须使用default修饰,默认会被public修饰* 实例方法:对象的方法,必须使用实现类的对象来访问。*/default void test1(){System.out.println("===默认方法==");test2();}/*** 2、私有方法:必须使用private修饰。(JDK 9开始才支持的)*   实例方法:对象的方法。*/private void test2(){System.out.println("===私有方法==");}/*** 3、静态方法:必须使用static修饰,默认会被public修饰*/static void test3(){System.out.println("==静态方法==");}void test4();void test5();default void test6(){}
      }
      
      • 我们写一个B类,实现A接口。B类作为A接口的实现类,只需要重写抽象方法就尅了,对于默认方法不需要子类重写。
      public class B implements A{@Overridepublic void test4() {}@Overridepublic void test5() {}
      }
      
      public class Test {public static void main(String[] args) {// 目标:掌握接口新增的三种方法形式B b = new B();b.test1();	//默认方法使用对象调用// b.test2();	//A接口中的私有方法,B类调用不了A.test3();	//静态方法,使用接口名调用}
      }
      

      就是说jdk8以后接口中的方法可以被default,static,private修饰,这些方法可以在接口中实现,而什么都不加,就不能实现,得实体类来实现。感觉开始和抽象类差不多了。

接口也能继承
  • 一个接口可以继承多个接口,接口同时也可以被类实现。

  • 1.一个接口继承多个接口,如果多个接口中存在相同的方法声明,则此时不支持多继承
    2.一个类实现多个接口,如果多个接口中存在相同的方法声明,则此时不支持多实现
    3.一个类继承了父类,又同时实现了接口,父类中和接口中有同名的默认方法,实现类会有限使用父类的方法
    4.一个类实现类多个接口,多个接口中有同名的默认方法,则这个类必须重写该方法。

public class Test {public static void main(String[] args) {// 目标:理解接口的多继承。}
}interface A{void test1();
}
interface B{void test2();
}
interface C{}//比如:D接口继承C、B、A
interface D extends C, B, A{}//E类在实现D接口时,必须重写D接口、以及其父类中的所有抽象方法。
class E implements D{@Overridepublic void test1() {}@Overridepublic void test2() {}
}
15.内部类
  • 当一个类的内部,包含一个完整的事物,且这个事物没有必要单独设计时,就可以把这个事物设计成内部类

内部类是类中的五大成分之一(成员变量、方法、构造器、内部类、代码块),如果一个类定义在另一个类的内部,这个类就是内部类。

成员内部类
  • 既可以访问内部类成员、也可以访问外部类成员
  • 如果内部类成员和外部类成员同名,可以使用**类名.this.成员**区分

成员内部类就是类中的一个普通成员,类似于成员变量、成员方法。

  • public class Outer {private int age = 99;public static String a="黑马";// 成员内部类public class Inner{private String name;private  int age = 88;//在内部类中既可以访问自己类的成员,也可以访问外部类的成员public void test(){System.out.println(age); //88System.out.println(a);   //黑马int age = 77;System.out.println(age); //77System.out.println(this.age); //88System.out.println(Outer.this.age); //99}}
    }
    

    成员内部类如何创建对象,格式如下:

    //外部类.内部类 变量名 = new 外部类().new 内部类();
    Outer.Inner in = new Outer().new Inner();
    //调用内部类的方法
    in.test();
    
静态内部类

在成员内部类的前面加了一个static关键字。静态内部类属于外部类自己持有。

  • public class Outer {private int age = 99;public static String schoolName="黑马";// 静态内部类public static class Inner{//静态内部类访问外部类的静态变量,是可以的;//静态内部类访问外部类的实例变量,是不行的public void test(){System.out.println(schoolName); //99//System.out.println(age);   //报错}}
    }
    

    静态内部类创建对象时,需要使用外部类的类名调用。

    //格式:外部类.内部类 变量名 = new 外部类.内部类();
    Outer.Inner in = new Outer.Inner();
    in.test();
    
局部内部类

局部内部类是定义在方法中的类,和局部变量一样,只能在方法中有效。所以局部内部类的局限性很强,一般在开发中是不会使用的

public class Outer{public void test(){//局部内部类class Inner{public void show(){System.out.println("Inner...show");}}//局部内部类只能在方法中创建对象,并使用Inner in = new Inner();in.show();}
}
匿名内部类

匿名内部类是一种特殊的局部内部类;所谓匿名,指的是程序员不需要为这个类声明名字。

匿名内部类本质上是一个没有名字的子类对象、或者接口的实现类对象。

匿名内部类的作用:简化了创建子类对象、实现类对象的书写格式。

new 父类/接口(参数值){@Override重写父类/接口的方法;
}
  • 示例:

  • public abstract class Animal{public abstract void cry();
    }
    

    我想要在不定义子类的情况下创建Animal的子类对象,就可以使用匿名内部类

    public class Test{public static void main(String[] args){//这里后面new 的部分,其实就是一个Animal的子类对象//这里隐含的有多态的特性: Animal a = Animal子类对象;Animal a = new Animal(){@Overridepublic void cry(){System.out.println("猫喵喵喵的叫~~~");}}a.eat(); //直线上面重写的cry()方法}
    }
    
    • 匿名内部类在编写代码时没有名字,编译后系统会为自动为匿名内部类生产字节码,字节码的名称会以外部类$1.class的方法命名
  • **只有在调用方法时,当方法的形参是一个接口或者抽象类,为了简化代码书写,而直接传递匿名内部类对象给方法。**这样就可以少写一个类。

    • public interface Swimming{public void swim();
      }
      
      public class Test{public static void main(String[] args){Swimming s1 = new Swimming(){public void swim(){System.out.println("狗刨飞快");}};go(s1);Swimming s1 = new Swimming(){public void swim(){System.out.println("猴子游泳也还行");}};go(s1);}//形参是Swimming接口,实参可以接收任意Swimming接口的实现类对象public static void go(Swimming s){System.out.println("开始~~~~~~~~");s.swim();System.out.println("结束~~~~~~~~");}
      }
      
16.枚举

枚举是一种特殊的类,它的格式是:

public enum 枚举类名{枚举项1,枚举项2,枚举项3;
}

枚举项就表示枚举类的对象,只是这些对象在定义枚举类时就预先写好了,以后就只能用这几个固定的对象。

  • 枚举项实际上是枚举类的对象

  • 枚举类A是用class定义的,说明枚举确实是一个类,而且X,Y,Z都是A类的对象;而且每一个枚举项都是被public static final 修饰,所以被可以类名调用,而且不能更改。

在这里插入图片描述

  • 既然枚举是一个类的话,我们能不能在枚举类中定义构造器、成员变量、成员方法呢?答案是可以的

    • public enum A{//定义枚举项X,Y,Z("张三"); //枚举项后面加括号,就是在执行枚举类的带参数构造方法。//定义空构造器public A(){}//成员变量private String name;//定义带参数构造器public A(String name){this.name=name;}//成员方法public String getName(){return name;}...
      }
      

      虽然枚举类中可以像类一样,写一些类的其他成员,但是一般不会这么写,如果你真要这么干的话,到不如直接写普通类来的直接。

  • 枚举一般表示几个固定的值,然后作为参数进行传输

public enum Constant{BOY,GRIL
}
public class Test{public static void main(String[] args){//调用方法,传递男生provideInfo(Constant.BOY);}public static void provideInfo(Constant c){switch(c){case BOY:System.out.println("展示一些信息给男生看");break;case GRIL:System.out.println("展示一些信息给女生看");break;}}
}
17.泛型
泛型类
  • 泛型类,在实际工作中一般都是源代码中写好,我们直接用的,就是ArrayList<E>这样的,自己定义泛型类是非常少的。

所谓泛型指的是,在定义类、接口、方法时,同时声明了一个或者多个类型变量(如:),称为泛型类、泛型接口、泛型方法、它们统称为泛型。

  • ArrayList类就是一个泛型类

  • ArrayList集合的设计者在定义ArrayList集合时,就已经明确ArrayList集合时给别人装数据用的,但是别人用ArrayList集合时候,装什么类型的数据他不知道,所以就用一个<E>表示元素的数据类型。

    当别人使用ArrayList集合创建对象时,new ArrayList<String> 就表示元素为String类型,new ArrayList<Integer>表示元素为Integer类型。

    • 泛型的好处:在编译阶段可以避免出现一些非法的数据。

    • 泛型的本质:把具体的数据类型传递给类型变量。

在这里插入图片描述

自定义泛型类
//这里的<T,W>其实指的就是类型变量,可以是一个,也可以是多个。
public class 类名<T,W>{}
  • 示例:
//定义一个泛型类,用来表示一个容器
//容器中存储的数据,它的类型用<E>先代替用着,等调用者来确认<E>的具体类型。
public class MyArrayList<E>{private Object[] array = new Object[10];//定一个索引,方便对数组进行操作private int index;//添加元素public void add(E e){array[index]=e;index++;}//获取元素public E get(int index){return (E)array[index];}
}
自定义泛型接口
  • 在实际工作中,一般也都是框架底层源代码把泛型接口写好,我们实现泛型接口就可以了.

泛型接口其实指的是在接口中把不确定的数据类型用<类型变量>表示。定义格式如下:

//这里的类型变量,一般是一个字母,比如<E>
public interface 接口名<类型变量>{}

示例:做一个系统要处理学生和老师的数据,需要提供2个功能,保存对象数据、根据名称查询数据,要求:这两个功能处理的数据既能是老师对象,也能是学生对象。

public class Teacher{}
public class Student{}

定义一个Data<T>泛型接口,T表示接口中要处理数据的类型。

public interface Data<T>{public void add(T t);public ArrayList<T> getByName(String name);
}
  • 这个接口可以让不同的类实现操作不同的数据

    • //此时确定Data<E>中的E为Teacher类型,
      //接口中add和getByName方法上的T也都会变成Teacher类型
      public class TeacherData implements Data<Teacher>{public void add(Teacher t){}public ArrayList<Teacher> getByName(String name){}
      }
      
      //此时确定Data<E>中的E为Student类型,
      //接口中add和getByName方法上的T也都会变成Student类型
      public class StudentData implements Data<Student>{public void add(Student t){}public ArrayList<Student> getByName(String name){}
      }
      
泛型方法
public <泛型变量,泛型变量> 返回值类型 方法名(形参列表){}
  • 在返回值类型和修饰符之间有定义的才是泛型方法
  • 在这里插入图片描述
public class Test{public static void main(String[] args){//调用test方法,传递字符串数据,那么test方法的泛型就是String类型String rs = test("test");//调用test方法,传递Dog对象,那么test方法的泛型就是Dog类型Dog d = test(new Dog()); }//这是一个泛型方法<T>表示一个不确定的数据类型,由调用者确定public static <T> test(T t){return t;}
}
泛型限定

泛型限定的意思是对泛型的数据类型进行范围的限制。有如下的三种格式

  • <?> 表示任意类型
  • <? extends 数据类型> 表示指定类型或者指定类型的子类
  • <? super 数据类型> 表示指定类型或者指定类型的父类

假设有Car作为父类,BENZ,BWM两个类作为Car的子类

class Car{}
class BENZ extends Car{}
class BWN extends Car{}public class Test{public static void main(String[] args){//1.集合中的元素不管是什么类型,test1方法都能接收ArrayList<BWM> list1 = new ArrayList<>();ArrayList<Benz> list2 = new ArrayList<>();ArrayList<String> list3 = new ArrayList<>();test1(list1);test1(list2);test1(list3);//2.集合中的元素只能是Car或者Car的子类类型,才能被test2方法接收ArrayList<Car> list4 = new ArrayList<>();ArrayList<BWM> list5 = new ArrayList<>();test2(list4);test2(list5);//2.集合中的元素只能是Car或者Car的父类类型,才能被test3方法接收ArrayList<Car> list6 = new ArrayList<>();ArrayList<Object> list7 = new ArrayList<>();test3(list6);test3(list7);}public static void test1(ArrayList<?> list){}public static void test2(ArrayList<? extends Car> list){}public static void test3(ArrayList<? super Car> list){}
}
泛型擦除

就是说泛型只能编译阶段有效,一旦编译成字节码,字节码中是不包含泛型的而且泛型只支持引用数据类型,不支持基本数据类型

在这里插入图片描述

反编译后:ArrayList后面没有泛型

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1559348.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Springboot——使用poi实现excel动态图片导入解析

文章目录 前言依赖引入导入实现方式一方式二 前言 最近要实现一个导入导出的功能点&#xff0c;需要能将带图片的列表数据导出到excel中&#xff0c;且可以导入带图片的excel列表数据。 考虑到低代码平台的表头与数据的不确定性&#xff0c;技术框架上暂定使用Apache-POI。 …

java 自定义填充excel并导出

首先在resources下面放一个excel模板 1. 方法签名和请求映射 RequestMapping(value "/ExportXls") public ResponseEntity<byte[]> rwzcExportXls(HttpServletRequest request, RequestBody JSONArray jsonArray) throws IOException { RequestMapping(val…

ubuntu 开放 8080 端口快捷命令

文章目录 查看防火墙状态开放 80 端口开放 8080 端口开放 22端口开启防火墙重启防火墙**使用 xhell登录**&#xff1a; 查看防火墙状态 sudo ufw status [sudo] password for crf: Status: inactivesudo ufw enable Firewall is active and enabled on system startup sudo…

微服务实战——登录(普通登录、社交登录、SSO单点登录)

登录 1.1. 用户密码 PostMapping("/login")public String login(UserLoginVo vo, RedirectAttributes redirectAttributes, HttpSession session){R r memberFeignService.login(vo);if(r.getCode() 0){MemberRespVo data r.getData("data", new Type…

进阶功法:SQL 优化指南

目录标题 SQL 优化指南1. 插入数据优化1.1 批量插入数据1.2 手动提交事务1.3 主键顺序插入1.4 大批量插入数据步骤&#xff1a; 2. 主键优化主键设计原则拓展知识 3. ORDER BY 优化3.1 Using filesort3.2 Using index示例 3.3 ORDER BY 优化原则 4. GROUP BY 优化示例 4.1 GROU…

优雅的实现服务调用 -- OpenFeign

文章目录 1. RestTemplate存在问题2. OpenFeign介绍3. 快速上手引入依赖添加注解编写OpenFeign的客户端远程调用 4. OpenFeign参数传递从URL中获取参数传递单个参数传递多个参数传递对象传递JSON 5. 最佳实践Feign继承方式创建一个新的模块引入依赖编写接口打jar包服务实现方实…

javacpp调用pdfium的c++动态库

1、.h头文件 2、生成java代码的conf PdfiumDocumentConfigure.java package org.swdc.pdfium.conf;import org.bytedeco.javacpp.annotation.Platform; import org.bytedeco.javacpp.annotation.Properties; import org.bytedeco.javacpp.tools.InfoMap; import org.byte…

物联网:一种有能力重塑世界的技术

物联网&#xff08;IoT&#xff09;近年来对我们的日常生活产生了如此积极的影响&#xff0c;以至于即使是不懂技术的人也开始相信它所带来的便利以及敏锐的洞察力。 物联网是一场数字技术革命&#xff0c;其意义甚至比工业革命更为重大。物联网是仍处于起步阶段的第四次工业革…

SldWorks问题 2. 矩阵相关接口使用上的失误

问题 在计算三维点在图纸&#xff08;DrawingDoc&#xff09;中的位置时&#xff0c;就是算不对&#xff0c;明明就4、5行代码&#xff0c;怎么看都是很“哇塞”的&#xff0c;毫无问题的。 但结果就是不对。 那就调试一下吧&#xff0c;调试后发现生成的矩阵很不对劲&#…

电力设备图像分割系统源码&数据集分享

电力设备图像分割系统系统源码&#xff06;数据集分享 [yolov8-seg-efficientViT&#xff06;yolov8-seg-C2f-DCNV2等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来源AAAI G…

分治算法(7)_归并排序_计算右侧小于当前元素的个数

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 分治算法(7)_归并排序_计算右侧小于当前元素的个数 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&…

鸿蒙微内核IPC数据结构

鸿蒙内核IPC数据结构 内核为任务之间的通信提供了多种机制&#xff0c;包含队列、事件、互斥锁、信号量等&#xff0c;其中还有Futex(用户态快速锁)&#xff0c;rwLock(读写锁)&#xff0c;signal(信号)。 队列 队列又称为消息队列&#xff0c;是一种常用于任务间通信的数据…

ASP.NET MVC-懒加载-逐步加载数据库信息

环境&#xff1a; win10, .NET 6.0 目录 问题描述解决方案基础版数据库查询部分&#xff08;Entity Framework&#xff09;控制器前端页面 加载到表格版 问题描述 假设我数据库中有N个表&#xff0c;当我打开某页面时&#xff0c;每个表都先加载一部分&#xff08;比如20条&am…

Chainlit集成Dashscope实现语音交互网页对话AI应用

前言 本篇文章讲解和实战&#xff0c;如何使用Chainlit集成Dashscope实现语音交互网页对话AI应用。实现方案是对接阿里云提供的语音识别SenseVoice大模型接口和语音合成CosyVoice大模型接口使用。针对SenseVoice大模型和CosyVoice大模型&#xff0c;阿里巴巴在github提供的有开…

有关vue路由的学习

导言 由于很久没碰前端了&#xff0c;碰到路由都不太会了。趁着后端对接来记录一下&#xff0c;就当复习。不过由于个人能力有限&#xff0c;这篇会偏向整个过程的实现逻辑&#xff0c;其中有很多具体的方法不会给来&#xff0c;有兴趣的可以去看一下源码~ 目的&#xff1a; …

基于springboot vue 校园失物招领平台的设计与实现

博主介绍&#xff1a;专注于Java&#xff08;springboot ssm springcloud等开发框架&#xff09; vue .net php phython node.js uniapp小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作☆☆☆ 精彩专栏推荐订阅☆☆☆☆…

SAP_SD模块-销售订单抬头折扣金额分摊到行项目的业务记录

前言&#xff1a; 本文主要是记录24年9月份支持财务月结过程中&#xff0c;用户提出的一个问题&#xff1a;“为什么KE30有部分物料9月份的销售数量少于FAGLL03H的销售数量&#xff1f;&#xff1f;”&#xff0c;主要包括以下两个内容&#xff1b; 1、问题发生的场景复现&am…

毕设分享 基于协同过滤的电影推荐系统

文章目录 0 简介1 设计概要2 课题背景和目的3 协同过滤算法原理3.1 基于用户的协同过滤推荐算法实现原理3.1.1 步骤13.1.2 步骤23.1.3 步骤33.1.4 步骤4 4 系统实现4.1 开发环境4.2 系统功能描述4.3 系统数据流程4.3.1 用户端数据流程4.3.2 管理员端数据流程 4.4 系统功能设计 …

【hot100-java】二叉树的最近公共祖先

二叉树篇 我觉得是比两个节点的深度&#xff0c;取min&#xff08;一种情况&#xff09; DFS解题。 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val x; }* }*/ clas…

Apache Flink Dashboard

1、Overview Apache Flink Web Dashboardhttp://110.40.130.231:8081/#/overview 这张图片显示的是Apache Flink的Web UI界面&#xff0c;其中包含了以下几个部分&#xff1a; Available Task Slots: 显示当前可用的任务槽位数量。任务槽位是指Flink集群中可用于运行任务的资…