[Java]面向对象

news2024/9/21 4:40:01

快速入门

计算机的核心作用就是处理数据, 变量用来存储单个数据, 数组用来储存一批数据, 对象用来存储一类数据

什么是对象: 对象就是一种特殊的数据结构, 在java中万物皆对象

面相对象编程的好处: 更加符合人类思维习惯

类和实例对象

在java中必须先设计类, 才能根据类创建对象

类是创建对象的模板, 对象是类的具体实例

语法

成员变量

  1. 类中的变量称为成员变量, 类中的方法称为成员方法
  2. 完整定义格式:

  1. 一般无需指定初始值, 存在默认值

注意事项

  1. 类名称首字母大写, 满足驼峰模式
  2. 一个代码文件中, 可以写多个class类, 但只能有一个用public修饰, public修饰的类名必须是java代码的文件名
  3. 实际开发中, 建议一个文件只定义一个class类
执行原理

执行流程

  1. java程序运行在jvm虚拟机中
  2. jvm虚拟机把内存划分为3块, 方法区, 栈内存, 堆内存
  3. jvm虚拟机执行代码时, 首先把Test启动类提取到方法区中执行
  4. 然后把Test启动类的main方法放到栈内存中运行
  5. main方法中使用了Cart类, 虚拟机把Cart类提取到方法区
  6. new Cart时,会在堆内存中开辟空间, 存放汽车对象, 汽车象会有一个类的地址. 指向方法区的汽车类
  7. 存放汽车对象的变量地址会被赋值给左侧的c1变量, 对象创建完成
  8. 对象变量c1通过变量地址, 找到堆内存中的汽车对象, 在找到对象对象的name属性, 完成属性赋值

注意事项:

  1. 对象与对象之间的数据不会相互影响, 除非多个变量指向同一个对象
  2. 如果某个对象没有变量引用它, 该对象无法被操作,会被视为垃圾对象, 垃圾对象会被垃圾回收机制清除

构造器

构造器的作用: 定义在类中, 用于创建一个类的对象, 并返回对象的地址

public class Car {
    //成员变量
    private String  name;
    //无参构造器 
    public Car() {
    }
    //有参构造器
    public Car(String n) {
         this.name = n;
    }
}

// 调用无参构造器
Car c1 = new Car()
// 调用有参构造器
Car c2 = new Car("奔驰")
  1. 构造器必须与类名一致, 且没有返回值
  2. 无参构造器: 创建对象, 里面的数据都是默认值
  3. 有参构造器: 创建对象, 同时可以为里面的数据赋值
  4. 类在定义时, java会为类自动生成无参构造器
  5. 如果类中定义了有参构造器, java就不会自动生成无参构造器了, 此时建议手动补充无参构造器

this关键字

可以出现在构造器和成员方法中, 代表当前对象的地址

public class Car {
    // this在构造器中使用
    public Car() {
        sout("this1:" + this)
    }
    // this在成员方法中使用
    public void run() {
        sout("this2:" + this)
    }
}

作用

this关键字指向当前类的调用者, 用来访问该对象的成员变量和成员方法

解决对象成员变量与方法内部变量可能的命名冲突

三大特性-封装

概念

封装是一种设计对象的原则, 它帮助我们正确的设计对象的属性和方法

好处

让变成变得简单, 有什么事情, 找对象调方法就行了

原则

对象代表什么, 就要封装对应的数据, 并提供数据对应的行为

合理隐藏: 成员变量全部隐藏, 提供get/set方法访问数据

合理暴露: 成员方法根据是否有用对外暴露

修饰符

公开成员: public修饰符, 公开成员可以通过对象直接访问

私有成员: private修饰符, 私有成员无法通过对象访问, 只能在类的内部访问

public class Student {
    // 成员变量私有
    private double score;
    // 成员方法按需暴漏
    public void setScore(double score) {
        this.score = score;
    }
    // 通过方法操作数据
    public double getScore(double score) {
        return score;
    }
}

javaBean

javaBean也称为 实体类, 是一种专门保存数据的java类

要求

  1. 成员变量必须私有(private), 提供getXX/setXX方法
  2. 必须提供无参构造器, 有参构造器可选

好处

  1. 实际开发中数据和数据的处理都会很多, 如果都混在一起, 代码的可读性和可维护性都是很差
  2. 所以流行的开发方式就是数据和数据处理相分离, 所以要用实体类保存数据

static关键字

static是静态的意思, 也就是静态修饰符, 可以用来修饰成员变量, 成员方法

静态变量
// 定义
public class User {
    // 静态变量
    static String name;
    // 实例变量
    int age;
    
}
// 访问方式1(推荐)
// 通过类名访问: 类名.静态成员变量
User.name;

// 访问方式2(不推荐)
// 通过对象访问: 对象.静态成员变量
User u = new User();
// 访问静态变量
u.name;
// 访问实例变量
u.age;
  1. static修饰的成员变量就是静态变量(类变量)
  2. 静态变量属于类, 可以被类的所有对象访问
  3. 推荐通过类名访问静态变量, 因为用过对象访问实例变量, 并不直观
  4. 无static修饰的成员变量就是实例变量
  5. 实例变量是属于每个对象的
  6. 只能通过实例对象访问, 且每个对象的信息不同

特点

  1. 静态变量只会跟随类加载一次, 内存中只有一份
  2. 静态成员变量: 某个数据只需要一份, 且希望能够被共享, 该数据就应该定义为类变量
// 系统启动后, 需要用户类记住自己创建了多少个对象
public class User {
    // 类变量
    public static int number;
    // 构造器
    public User() {
        User.number++;
    }
}
静态方法
// 定义
public class User {
    // 实例方法
    public void run() {
        sout("好好学习.天天向上")
    }
    // 静态方法
    public static int getMax(int a, int b) {
        return a > b ? a : b
    }
    
}
// 访问方式1(推荐)
// 通过类名访问: 类名.静态成员方法
User.getMax();

// 访问方式2(不推荐)
// 通过对象访问: 对象.静态成员方法
User u = new User();
// 访问静态方法
u.getMax();
// 访问实例方法
u.run();
  1. 静态成员方法(static修饰, 属于类), 建议使用类名触发, 也可以用对象触发(不直观)
  2. 实例成员方法(无static修饰, 属于对象),只能用对象触发
  3. 如果表示对象自己的行为, 且方法中需要访问实例成员的, 则该方法必须声明成实例方法
  4. 如果该方法是执行公用功能, 则可以声明成静态方法
  5. 静态方法只能访问静态成员, 不可以直接访问实例成员
  6. 实例方法可以访问静态成员, 也可以访问实例成员
  7. 静态方法中不可以使用this关键字
main方法

main方法是类方法, 使用java命令执行Test(类)程序的时候, 虚拟机会通过Test(类)访问main方法, 然后运行

java Test -> Test.main()

工具类

工具类就是一个类中只定义类方法, 每个方法完成一个功能, 这个类就是工具类

好处

  1. 调用方便: 如果使用实例方法, 还要new出实例, 麻烦而且浪费内存
  2. 代码复用: 一次编写, 处处可用
  3. 建议: 工具类不需要创建对象, 建议把工具类的构造器进行私有
public class XxxUtil {
    // 方法1
    public static void xxx() {
        ...
    }
    // 方法2
    public static boolean xxx(String email) {
        ...
    }
    // 方法3
    public static String xxx(int n) {
        ...
    }
    // 构造器私有
    private XxxUtil() { }
}
代码块

代码块是类的5大成分之一: 成员变量/构造器/方法/代码块/内部类

在java中, 使用 {} 括起来的代码被称为代码块

静态代码块

  • 格式: static { }
  • 特点: 类加载时自动执行, 由于类只会加载一次, 所以静态代码块也只会执行一次
  • 使用: 在类加载的时候做一些静态数据初始化的操作, 例如: 对类变量的初始化赋值

实例代码块(了解)

  • 格式: { }
  • 特点: 每次创建对象, 调用构造器执行时, 都会执行实例代码块, 并在构造器之前执行
  • 使用: 和构造器一样, 用来完成对象的初始化赋值

三大特性-继承

继承就是用extends关键字, 让一个类和另一个建立父子关系

// Student称为子类
// People称为父类
public class Student extends People {
    
}
  1. 作用: 子类继承父类后, 就可以直接使用父类公共的属性和方法了
  2. 好处: 继承的好处就是提高代码的复用性

  1. 规范: 子类们相同的特性(公共属性/公共方法)放在父类中定义, 子类独有的属性和方法放在子类中定义
原理

子类的对象是由子类和父类共同决定的

权限修饰符

权限修饰符的作用就是 限制类中的成员能够被访问的范围

  • 访问权限从小到大是: private(私有)< 缺省(不写) < protected(受限制) < public(公开)
继承的特点
  1. 子类可以继承父类的属性和方法
  2. 子类可以继承父类的私有成员, 只是不能直接访问

  1. 子类不能继承父类的构造器, 因为子类有自己的构造器
  2. 子类可以直接使用父类的静态成员(共享), 但是共享不等于继承
  3. jaba是单继承模式: 一个类只能继承一个直接父类

  1. java不支持多继承, 但是支持多层继承

  1. java中所有的类都是Object类的子类, 要么直接继承, 要么间接继承
继承后的变化
1.子类访问成员的原则

在子类方法中访问成员(成员变量/成员方法)遵循就进原则

  • 先在子类局部范围找, 然后在子类成员范围找, 然后在父类范围找, 找不到就报错
  • 如果子父类中出现了重名的成员, 会优先使用子类的(更近)
  • 如果一定要在子类中使用父类的成员, 可以通过super关键字,指定访问父类的成员
  • 格式: super.父类成员变量/父类成员方法
  • 也可以通过this关键字, 指定访问子类的成员 (没用, 因为默认就访问子类的成员)
  • 格式: this.成员变量/成员方法
2.子类的方法重写

当子类觉得父类中的某个方法不好用, 子类可以重写一个名称和参数列表相同的方法, 去覆盖父类的方法

  1. 重写后, 方法的访问, java会遵循就近原则
  2. 建议使用@Override注解, 他可以让编译器检查重写的格式, 使代码可读性更好

基本要求

  1. 重写方法的名称和形参列表必须与被重写方法保持一致
  2. 私有方法, 静态方法不能被重写
  3. 子类重写父类方法, 访问权限必须等于或大于父类该方法的权限
  4. 重写的方法的返回值, 必须与被重写方法的返回值一致,或者范围更小
  5. 以上了解即可, 实际开中遵循: 声明不变, 重新实现

举例

  1. 可以通过重写Object类的toString方法, 使其返回对象内容, 而不是地址
  2. 可以通过右键->Generate->toString 快速生成
3.子类构造器的特点

子类中所有的构造器, 默认都会先调用父类的无参构造器, 再执行自己

原因

  • 子类在初始化的时候,有可能会用到父类中的数据, 如果父类没有初始化, 子类就无法使用父类的数据
  • 所以, 子类初始化之前, 一定会调用父类的构造器, 完成父类的初始化
  • 默认情况下, 子类构造器的第一行代码都是super() , 写不写都有, 他会调用父类的无参数构造器
  • 如果父类没有无参构造器, 则会报错, 我们需要在子类调用父类的有参构造器, super(参数)
  • 在继承模式下, 处理数据的构造器被分到多个不同的类中去了,
  • 所以需要先调用父类构造器, 再调用自己的构造器, 确保数据的完整初始化
4.子类其他构造器

如果父类中没有无参构造器, 代码就会报错, 因为子类默认要调用父类的无参构造器, 我们可以通过 super(...) 调用父类的有参构造器, 解决问题

// 父类
public class People {
    private String name;
    // 有参构造器 
    public Prople(String name) {
        this.name = name   
    }
}

// 子类
public class Student extends People {
   private int age;
    // 有参构造器
   public Student(int age) {
     // 调用兄弟构造器 
     this(age, '张三');
   }
   // 有参构造器
   public Student(int age, String name) {
       // 调用父类有参构造器
       super(name)
       // 初始化对象
       this.age = age;
   }
}

// 初始化学生对象
Student s = new Student(18)

注意

  • 子类通过 this(...) 调用本类的其他构造器, 其他构造器可以通过 super(...) 去调用父类的构造器
  • super(...) 和 this(...) 都只能放在构造器的第一行, 所以不能同时使用
this和super

this代表本类对象的引用, super代表父类存储空间的标识

包就是分门别类的管理类的, 类似于文件夹

建包

// 语句
// package 公司域名倒写.技术名称
// 必须在第一行, 一般IEDA工具会帮助创建
package com.itheima.javabean;
public class Student {
    
}

导包

相同包下的类可以直接访问, 不同包下的类必须导包

  1. 语句: import 包名.类名;
  2. 使用java官方的程序, 也需要导包, lang包下的程序可以直接用
  3. 一个类中使用多个不同包下的类, 如果类的名字一样, 默认只能导入一个, 另一个必须带包名访问

自动导包

权限修饰符

用来控制一个成员能够被访问的范围, 可以修饰成员变量, 构造器, 内部类

  1. 能够识别他人定义的成员的访问范围
  2. 自己定义成员一般要满足如下要求:
  • 成员变量一般私有
  • 方法一般公开
  • 希望该成员只能被本类访问, 使用private修饰
  • 希望该成员只能被本类和同一个包下的其他类及子类访问, 使用protected修饰
  • 其他情况用public就行

final关键字

final关键字是最终的意思, 可以修饰类/方法/变量

  1. 修饰类: 该类就是最终类, 特点是不能被继承, 工具类中可能会用到
  2. 修饰方法: 该方法就是最终方法, 特点是不能被重写
  3. 修饰变量: 该变量就只能被赋值一次,不能再次赋值
  • 基本类型的变量: 该变量存储的数据不能被改变,
  • 引用类型的变量: 该变量存储的地址不能被改变, 但是对象里面的值可以改变
常量

使用public static final 修饰的成员变量就是常量, 必须要有初始值

  1. 命名规范: 全大写英文, 使用下划线连接
  2. 作用: 通常用于记录系统的配置信息

  1. 优势:
  • 实现软编码, 代码可读性更好,可维护性更好
  • 程序编译后,常量会被"宏替换", 即出现常量的地方全部会被替换成其记住的字面量,保证常量和字面量的性能是一样的

枚举

枚举是java中一种特殊的类, 专门用来做信息分类, 可读性好, 入参约束谨慎, 代码优雅

定义

public enum Season {
    SPRING, SUMMER, AUTUMN, WINTER;
}

反编译后

  1. 枚举类都是继承了枚举类型: java.lang.Enum
  2. 枚举都是最终类, 不可以被继承
  3. 枚举类的构造器都是私有的, 枚举对外不能创建对象
  4. 枚举类的第一行只 能罗列一些名称, 这些名称都是常量, 并且每个常量记住的都是枚举类的一个对象
  5. 枚举类中, 从第二行开始, 可以定义类的其他各种成员
  6. 枚举类相当于是多例模式
  7. 枚举会从 java.lang.Enum 类中继承一些方法
  • Season[] se = Season.values() // 拿到全部对象
  • Season se = Season.valueOf("SPRING"); // 拿到指定名称的枚举对象
  • se.name() // 拿到枚举对象的名字
  • se.ordinal() // 拿到枚举对象的索引

补充

  1. 可以使用枚举实现单例模式
public enum C {
     x;  //单例
}
  1. 枚举和常量都是用来表示一组信息, 然后作为参数进行传输
  • 枚举相对于常量, 限制性更好,
  • 常量相对于枚举, 灵活性更好,
  • 两者的使用场景相似

抽象类

abstract关键字是抽象的意思, 可以修饰类, 成员方法

// 抽象类
修饰符 abstract class 类名 {  
    // 抽象方法
    修饰符 abstract 返回值类型 方法名称(形参列表);
}
  1. 抽象方法只有方法签名, 不能声明方法体
  2. 一个类中如果定义了抽象方法,这个类必须声明为抽象类, 否则报错
  3. abstract修饰的类称为抽象类, abstract修饰的方法称为抽象方法
  4. 类该有的成员(成员变量/方法/构造器),抽象类都可以有
  5. 抽象类可以理解为不完整的设计图, 得到了抽象方法, 但是失去了创建对象的能力
  6. 所以抽象类不能创建对象, 仅作为一种特殊的类, 让子类继承并实现抽象方法
  7. 一个类继承抽象类, 必须重写完抽象类的全部抽象方法, 否则这个类也要定义成抽象类
  8. abstract不能修饰变量, 代码块, 构造器

示例

父类知道每个子类都要做某个行为, 但每个子类要做的情况不一样

  1. 父类就可以定义抽象方法, 交给子类去重写实现,
  2. 设计这样的抽象类, 就是为了更好的支持多态

扩展

  1. final和abstract是互斥关系
  2. abstract定义的抽象类作为模板让子类继承, final定义的类不能被继承
  3. 抽象方法定义通用功能让子类重写, final定义的方法子类不能重写
  4. 使用抽象类可以实现 [模版方法] 设计模式

三大特性-多态

多态就是对象可以有多种形态, 是继承/实现情况下的一种现象, 表现为:对象多态和行为多态

对象多态: 一个对象可以有角色(形态), 你既是你爸爸的儿子, 也是你媳妇的老公

行为多态: 一个对象的行为可以有不同的表现, 人都会唱歌, 但是你唱的和刘德华唱的不一样

注意: 多态是对象或行为的多态, java中的属性(成员变量)不谈多态

多态的前提
  1. 有继承/实现关系;
  2. 存在父类引用子类对象;
  3. 存在方法重写 (多态侧重行为多态)
常见形式

父类类型 对象名称 = new 子类构造器

public class Prople {
    public String name = "父类的名称"
    public void run() {
        sout("人可以跑")
    }
}
public class Teacher extends Prople {
    public String name = "老师的名称"
    public void run() {
        sout("老师跑的气喘吁吁")
    }
}
public class Student extends Prople {
    public String name = "学生的名称"
    public void run() {
        sout("学生跑的飞快")
    }
}
public class Test {
    public static void main(String[] ages) {
        // 对象多态: 人对象可以指向学生对象,也可以指向老师对象
        People p1 = new Student();
        People p2 = new Teacher();
        
        // 行为多态: 同样调用run方法,执行结果不同
        p1.run(); // 学生跑的飞快
        p2.run(); // 老师跑的气喘吁吁
        
        // 成员变量不存在多态
        p1.name;  // 父类的名称
        p1.name;  // 父类的名称

    }
}

运行特点

  1. 方法调用: 编译看左边(People), 运行看右边(Student();)
  2. 变量调用: 编译看左边(People), 运行也看左边(People)
多态的好处

1:在多态形势下, 右边对象是解耦合的, 更便于扩展和维护

// 可以方便的切换
// prople p1 = new Teacher(); 
prople p1 = new Student();
p1.run()

2:定义方法时, 使用父类类型的形参, 可以接受一切子类对象, 扩展性更强

Student s = new Student();
go(s);

Teacher t = new Teacher();
go(t);

publci static void go(People p) {
    
}
多态的问题

多态下不能使用子类的独有功能

public class Prople {
    public void run() {
        sout("人可以跑")
    }
}
public class Teacher extends Prople {
    public void run() {
        sout("老师跑的气喘吁吁")
    }
    public void sayHi() {
        sout("老师需要讲课")
    }
}
public class Test {
    public static void main(String[] ages) {
        People p1 = new Student();
        p1.run();   // 老师跑的气喘吁吁
        p1.sayHi(); // 报错 
    }
}

解决方法

强制类型转换: 把父类类型强转成子类类型, 解决多态下无法使用子类独有功能的问题

方法: 子类 变量名 = (子类) 父类变量

public class Test {
    public static void main(String[] ages) {
        People p1 = new Student();
        // 强制类型转换
        Student s1 = (Student) p1;
        
        // 正常运行: "老师需要讲课"
        p1.sayHi();
        
        // 类型谈判, 防止类型转换错误
        if(p1 instanceof Student) {
             Student s1 = (Student) p1;
             p1.sayHi();
        }
        
    }
}

补充

  1. 只要存在继承/实现关系, 就可以在编译阶段进行强制类型转换, 编译阶段不会报错
  2. 运行时, 如果发现强转的类型和对象的真实类型不符, 就会报类型转换异常(ClassCastException)的错误
  3. 官方建议, 强制类型转换前先 使用 instanceof 关键字, 判断当前对象的真实类型

接口

接口是一种规范, 在java中, 使用 interface关键字定义接口, 可以理解为一种特殊的结构

定义
public interface A {
     // 成员变量(默认就是常量)
     String SCHOOL_NAME = "程序员";
     //  成员方法(默认就是抽象方法)
     void test();
}
  1. JDK8之前的接口中只能有抽象方法和常量
  2. 接口中的成员都是public修饰的, 写不写都是
  3. 接口方法默认被public修饰的原因: 接口是需要被类实现的, 大部分接口方法都是要对外暴漏的
  4. 接口不能实例化
使用

接口不能创建对象, 接口是用来被 类 实现的, 实现接口的类称为实现类

// 实现接口的关键字: implements
修饰符 class 实现类 implements 接口1, 接口2, ... {
    
}
  1. 一个类可以实现多个接口(干爹)
  2. 一个类实现接口, 必须重写完 全部接口的 全部抽象方法, 否则实现类需要定义为抽象类
优势
  1. 弥补了类单继承的不足,一个类可以同时实现多个接口
  2. 面向接口编程, 可以灵活方便的切换各种业务实现
新增

jdk8开始, 接口新增了三种方法, 目的是增强接口的能力, 更便于项目的扩展和维护

了解即可, java源码中会看到

1.默认方法

// 默认方法必须使用default修饰
// 默认方法, 使用实现类的对象调用
default void run() {
    sout("默认方法")
}

2.静态方法

// 静态方法必须使用static修饰
// 静态方法, 使用本身的接口名来调用
static void run() {
    sout("静态方法")
}

3.私有方法

// 私有方法必须使用private修饰
// jdk9开始支持, 只能在本类中被其他的默认方法或私有方法访问
static void run() {
    sout("私有方法")
}

接口的多继承

一个接口可以同时继承多个接口, 便于实现类实现多个接口

public interface 接口1 extends 接口1, 接口2 {
    
}
接口使用细节

一个接口继承多个接口, 如果多个接口中存在方法签名冲突, 则此时不支持多继承

一个类实现多个接口, 如果多个接口中存在方法签名冲突, 则此时不支持多实现

一个类继承了父类, 又同时实现了接口, 父类中和接口中存在同名的默认方法, 实现类会优先使用父类的

一个类实现了多个接口, 多个接口中存在同名的默认方法, 会冲突, 解决方法就是在实现类中重写该方法

内部类

如果一个类中定义在另一个类的内部, 这个类就是内部类

内部类是类的五大成分之一(成员变量/方法/构造器/内部类/代码块)

public class People {
    // 内部类
    public class Heart {
        
    }
}
  1. 场景: 当一个类的内部, 包含了一个完成的事物, 且这个事物没必要单独设计时, 就可以设计成内部类
  2. 内部类通常可以方便访问外部类的成员, 包括私有成员
  3. 内部类提供了更好的封装性, 可以使用private, protectecd修饰内部类
静态内部类

用static修饰的内部类, 属于外部类自己持有, 特点与普通类一致

// 定义
public class Car {
   // 静态成员内部类
   public static class Engine { }
}

// 创建对象
Car.Engine eg = new Car.Engine();

// 访问成员
// 可以直接访问外部类的静态成员
// 不可以直接访问外部类的实例成员
成员内部类

无static修饰, 属于外部类的对象, JDK16之后, 成员内部类也可以定义静态成员了

// 定义
public class Car {
    // 成员内部类
   public class Engine { }
}

// 创建对象
Car.Engine  eg = new Car().new Engine();

// 访问成员
// 可以直接访问外部类的实例成员和静态成员
// 可以拿到当前外部类对象, 格式是: 外部类名.this
匿名内部类(重点)

本质是一个没有名字的局部内部类, 作用就是方便的创建一个子类对象, 目的是简化代码

// 1.定义一个抽象类
abstract class Animal {
    public abstract void cry();
}

// 2.使用匿名内部类语法
// 把匿名内部类编译成一个子类, 然后立即创建一个子类对象
Animal a = new Animal(){
    @Override
    public void cry() {
        sout("喵喵喵")
    }
};

// 直接使用子类 
a.run(); // 喵喵喵
  1. 语法:

  1. 匿名内部类本质是一个子类, 并且会立即创建一个子类对象
  2. 匿名内部类的对象类型, 相当于是当前new的那个类型子类类型
  3. 使用场景: 把匿名内部类当做参数传给方法
  4. 匿名内部类都是在需要的时候用, 比如一个方法需要一个对象作为参数
  5. 那么单独创建对象传进去就麻烦, 此时可以使用匿名内部类简化代码

泛型

泛型提供了在编译阶段的类型约束, 并自动进行检查, 可以避免强制类型转换和可能出现的转换异常

// 该集合只能添加字符串类型的数据
ArrayList<String> list1 = new ArrayList<>();
list1.add("java1");
  1. 定义类,接口,方法时, 同时声明一个或多个类型变量,用于限制成员类型,
  2. 使用泛型的类称为泛型类, 泛型接口或泛型方法, 统称为泛型
  3. 原理: 把具体的数据类型作为参数传给类型变量, 通过类型变量限制成员的类型
自定义泛型类
// 模拟ArrayList集合
public class MyArrayList<E> {
    // 模拟add方法
    public boolean add(E e) {
          return true;
     }
    // 模拟get方法
    public E get(int index) {
          return null;
    }
}



// 使用泛型
MyArrayList<String> list = new MyArrayList<>();
list.add("java1")
list.get(1)
  1. 如果需要, 可以进一步使用extends限制泛型的范围

public class MyArrayList<E extends Animal> { }

  1. 表示类型E必须是Animal类型或者是Animal的子类
自定义泛型接口
public interface Date<T> {
    void add(T t);
    ArrayList<T> getByName(String name):
}
  1. 类型变量建议使用大写英文字母, E T K V 等
自定义泛型方法
public static <T> T test(T t) {
     return t;
}
通配符
  1. 在使用泛型是可以用 ? 表示一切类型
泛型上下限
  1. 泛型上限: ? extends Cart
  2. 表示能接受的类型必须是Car或其子类
  1. 泛型下限: ? super Cart
  2. 表示能接受的必须是Cart或其父类
泛型擦除
  1. 泛型是在编译阶段工作的. 就是帮助程序进行类型校验的, 程序编译成class文件后, 泛型就不会存在了
  2. 泛型不支持基本数据类型, 只支持引用数据对象, 如Integer Double

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

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

相关文章

Python基本命令、函数、以及小项目

目录 1.基本操作 1.1 例子 1.2 输出结果 2.数据结构 2.1 例子 2.2 输出结果 3.字符串操作 3.1 例子 3.2 输出结果 4.文件操作 4.1 例子 4.2 输出结果 5.数学操作 5.1 例子 5.2 输出结果 6.模块导入 6.1 例子 6.2 输出结果 7.控制结构 7.1例子 输出结果 7…

Flink-StarRocks详解:第五部分查询数据湖(第55天)

系列文章目录 4.查询数据湖 4.1 Catalog 4.1.1 概述 4.1.1.1 基本概念 4.1.1.2 Catalog 4.1.1.3 访问Catalog 4.1.2 Default catalog 4.1.3 External Catalog 4.2 文件外部表 4.2.1 使用限制 4.2.2 开源版本语法 4.2.3 阿里云版本 5. 查询及优化 文章目录 系列文章目录前言4.查…

Java(十一)——内部类、成员内部类、静态内部类、局部内部类、匿名内部类

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 ⚡开源项目&#xff1a; rich-vue3 &#xff08;基于 Vue3 TS Pinia Element Plus Spring全家桶 MySQL&#xff09; &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1…

操作系统原理:程序、进程、线程的概念

文章目录 程序、进程、线程的概念程序&#xff08;Program&#xff09;进程&#xff08;Process&#xff09;线程&#xff08;Thread&#xff09;关系总结 在日常对操作系统的使用中&#xff0c;大家肯定对程序、进程和线程多少有所耳闻。作为操作系统的重要一部分&#xff0c;…

ROM修改进阶教程------修改自己适配的rom固件 禁止第三方修改 删除自定文件或app后自动重启的步骤解析

很多适配第三方系统的资深作者。都会在rom中加入一些防止他人任意修改的脚本。这种操作主要避免盗包的行为。而且前期有在rom中加入联网锁定id格式化分区的恶意操作。今天主要解析一种删除自带文件后重启手机后会反复重启的脚本步骤。 通过博文步骤可以初步了解; 1----了解删…

CAPL代码中判断网络是CAN还是CANFD

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…

ardupilot开发 --- 网络技术综述 篇

不信人间有白头 一些概念参考文献 一些概念 以太网、局域网、互联网 以太网(Ethernet)&#xff0c;是一种计算机局域网技术。以太网是一种有线网络技术&#xff0c;网络传输介质包括&#xff1a;以太网电缆&#xff0c;如常见的双绞线、光纤等。根据传输速度&#xff0c;可以氛…

2024107读书笔记|《火车快开(李娟诗集)》——我轰然经过你的生命,又悄然退却,你从不曾爱过我,你只爱我在你的生命中坠落

《火车快开&#xff08;李娟诗集&#xff09;》—— 文前第一部分 荒野碎片第二部分 弯路第三部分 告别 《火车快开&#xff08;李娟诗集&#xff09;》作者李娟&#xff0c;看的她的第一本书是《记一忘二三》&#xff0c;前段时间《我的阿勒泰》超级火&#xff0c;但我终于还是…

Codeforces Round 962 (Div. 3) A~F

A.Legs&#xff08;贪心&#xff09; 题意&#xff1a; 农夫约翰的农场又迎来了美好的一天。 农夫约翰来到农场后&#xff0c;数了数共 n n n条腿。众所周知&#xff0c;农场里只住着鸡和牛&#xff0c;一只鸡有 2 2 2条腿&#xff0c;而一头牛有 4 4 4条腿。 假设约翰农场…

Shell编程 --基础语法(1)

文章目录 Shell编程基础语法变量定义变量使用变量命令的使用只读变量删除变量 传递参数字符串获取字符串长度字符串截取 数组定义方式关联数组获取数组的长度 总结 Shell编程 Shell是一种程序设计语言。作为命令语言&#xff0c;它交互式解释和执行用户输入的命令或者自动地解…

数论——裴蜀定理、欧几里得算法、扩展欧几里得算法、逆元以及求解

裴蜀定理 若整数 a、b 互质&#xff08;最大公约数为 1&#xff09;&#xff0c;则存在整数 x、y &#xff0c;使得 ax by 1 。 更一般的情况是&#xff1a;设 a、b 是不全为零的整数&#xff0c;则存在整数 x、y &#xff0c;使得 ax by gcd(a, b) &#xff0c;其中 gcd…

第十一章:Kubernetes API服务器的安全防护

本章内容包括&#xff1a; 了解认证机制ServiceAccounts是什么及使用的原因了解基于角色(RBAC)的权限控制插件使用角色和角色绑定使用集群角色和集群角色绑定了解默认角色及其绑定 1 了解认证机制 在前面的内容中&#xff0c;我们说到API服务器可以配置一个到多个认证的插件(授…

等保2.0 | 人大金仓数据库测评

人大金仓数据库&#xff0c;全称为金仓数据库管理系统KingbaseES&#xff08;简称&#xff1a;金仓数据库或KingbaseES&#xff09;&#xff0c;是北京人大金仓信息技术股份有限公司自主研制开发的具有自主知识产权的通用关系型数据库管理系统。以下是关于人大金仓数据库的详细…

室内养宠空气净化器哪家好?热门室内养宠空气净化器用户体验

自从家里有了4只英短后&#xff0c;一到季节我就得不停的拖地刷床&#xff0c;除了这些可以手动清理的猫毛之外&#xff0c;那么空气中的猫毛怎么办&#xff1f;真的不建议养猫&#xff0c;除非你能接受空气中飞舞着浮毛&#xff0c;衣服、床、筷子、鼻子里全都是猫毛&#xff…

STM32——外部中断(EXTI)

目录 前言 一、外部中断基础知识 二、使用步骤 三、固件库实现 四、STM32CubeMX实现 总结 前言 外部中断&#xff08;External Interrupt&#xff0c;简称EXTI&#xff09;是微控制器用于响应外部事件的一种方式&#xff0c;当外部事件发生时&#xff08;如按键按下、传感器信号…

NC 合并区间

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了就去分享给你的码吧。 描述 给出一组区间…

推流直播服务

pc端建立NVR服务器&#xff0c;并实现NVR功能&#xff0c;具有推流功能&#xff0c;推送给OBS&#xff0c;可以对接到抖音、快手等平台&#xff0c;实现实时直播&#xff0c;应用于无人值守&#xff0c;养殖、农场、旅游等场景 运行MediaServer和webserver 服务端口配置在confi…

C# 使用 NLog 输出日志到文件夹

在项目中使用 NuGet 安装 NLog 包以及 NLog.Config 包 配置 nlog.config 在项目的根目录下创建一个 Nlog.config 文件&#xff08;如果还没有&#xff09;&#xff0c;然后添加如下配置&#xff1a; <?xml version"1.0" encoding"utf-8" ?> <…

leetcode数论(​3044. 出现频率最高的质数)

前言 经过前期的基础训练以及部分实战练习&#xff0c;粗略掌握了各种题型的解题思路。现阶段开始专项练习。 描述 给你一个大小为 m x n 、下标从 0 开始的二维矩阵 mat 。在每个单元格&#xff0c;你可以按以下方式生成数字&#xff1a; 最多有 8 条路径可以选择&#xff1…

17 字符函数、字符串函数和内存函数

目录 一、字符函数 &#xff08;一&#xff09;字符分类函数 &#xff08;二&#xff09;字符转换函数 二、字符串函数 &#xff08;一&#xff09;strlen、strcpy、strcat、strcmp的使用和模拟实现 1、strlen &#xff08;1&#xff09;使用 &#xff08;2&#xff09;…