09-面向对象

在这里插入图片描述

未来的道路也一定盛满阳光,希望所有的等待都是心想事成和如愿以偿🚀

一、初步了解

Java是面向对象的编程语言,Java它提供了定义类、成员变量、方法等最基本的功能。

类是描述某一类事物共同特征的模板;当然也可以使用类来定义变量,所有使用类定义的变量都是引用类型。

对象是类的实例,以对象的方式封装数据;Java中使用类的构造器来创建该类的对象。

面向对象三大特性:封装、继承、多态。


二、类

类:可以理解成图纸,它是对象共同特征的描述。

对象:是真实存在的具体实例。

在Java中,必须先设计类,才能创建对象并使用。


2.1 类的定义格式


public class 类名{
    1、成员变量 (也可以称作属性,描述对象的特性)
    2、成员方法 (包括:普通方法、静态方法,描述对象的行为)
    3、构造器   (创建对象、初始化数据)
    4、代码块   (包括:普通代码块{}、静态代码块static{})  
    5、内部类   (包括:成员内部类、局部内部类、匿名内部类和静态内部类)       
}

注意事项:

  • 类名首字母建议大写,满足驼峰命名规范。
  • 一个Java文件中可以定义多个class类,但只能有一个类是public修饰,而且public修饰的类名必须和文件名保持一致。实际开发中建议还是一个文件定义一个class类。
  • 成员变量的完整定义格式:修饰符 数据类型 变量名称 = 初始值; 一般无需指定初始值。

2.2 创建对象


使用 new 关键字来实例化一个对象(这种方式创建增加耦合度,无论使用什么框架,都要减少new的使用以降低耦合度)。

对象的功能:调用属性、调用方法。

创建对象语法格式如下:

类名 对象名 = new 类名();

例如:定义一个汽车类,属性有:名称、价格,行为有:启动、运行。

public class Car {
    // 成员变量
    String name;
    double price;

    public void start(){
        System.out.println(name+"启动了");
    }

    public void run(){
        System.out.println(price+"万的"+name+"跑起来了");
    }
}
public class Test1 {
    public static void main(String[] args) {
        // 创建汽车对象
        Car car = new Car();

        // 调用属性
        System.out.println(car.name);
        System.out.println(car.price);

        // 为属性赋值
        car.name = "法拉利拉法";
        car.price = 3150;

        // 调用方法
        car.start();
        car.run();
    }
}

在这里插入图片描述


2.3 对象在内存中的运行机制

两个对象的内存图
public class Car {
    // 成员变量
    String name;
    double price;

    public void start(){
        System.out.println(name+"启动了");
    }

    public void run(){
        System.out.println(price+"万的"+name+"跑起来了");
    }
}
public class Test1 {
    public static void main(String[] args) {
        Car c1 = new Car();
        c1.name = "法拉利拉法";
        c1.price = 3150;
        c1.start();
        c1.run();
        
        Car c2 = new Car();
        c2.name = "宝马";
        c2.price = 66;
        c2.start();
        c2.run();
    }
}

在这里插入图片描述

  • 对象放在堆内存中。
  • 变量名c1存储是对象在堆内存中的地址。
  • 成员变量的数据存放在对象中,即堆内存中。

两个变量指向同一个对象的内存图
public class Student {
    String name;
    char sex;
    String hobby;

    public void study(){
        System.out.println(name+"正在学习");
    }
    // 打印个人信息
    public void show(){
        System.out.println("姓名:"+name+",性别:"+sex+",爱好:"+hobby);
    }
}
public class Test2 {
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.name = "小张";
        s1.sex = '男';
        s1.hobby = "睡觉、摸鱼";
        s1.show();
        s1.study();

        Student s2 = s1;
        s2.name = "小李";
        s2.sex = '女';
        s2.hobby = "唱歌";
        s2.show();
        s2.study();
    }
}

在这里插入图片描述垃圾回收:当堆内存中的对象,没有被任何变量引用(指向)时,就会被判定为内存中的“垃圾”。


2.4 构造器


  • 构造器也叫构造方法,用来实例化一个对象的。
  • 构造方法的名称和类名相同,严格区分大小写,没有返回值。
  • 构造器是在创建对象时被调用。
  • 一个类可以有多个构造器,根据传入的参数(实参)匹配对应的构造器。

构造器的声明格式如下:

修饰符 类名([参数列表]){
	语句;
}

1、如果我们没有显示的声明构造器,系统会默认提供一个无参构造器。

public class Dog{
	String name;
	int age;

	void run(){
		System.out.println(name+"在草坪上奔跑!");
	}
	// 无参构造器
	// public Dog(){}

	public static void main(String[] args){
		Dog dog = new Dog();
		
	}
}

2、如果我们显示的声明了有参构造器,当我们要使用无参构造器时,需要手动把这个无参构造器声明出来。

有参构造器:在一个对象初始化的时候,给指定的属性赋值。(往往为了简便开发)

在这里插入图片描述

所以我们要在这个类中把无参构造器声明出来:

public class Dog{
    String name;
    int age;

    public Dog() {
         System.out.println("无参构造器");
    }

    void run(){
        System.out.println(name+"在草坪上奔跑!");
    }

    public Dog(String name){
        this.name=name;
    }

    public static void main(String[] args){
        // 实例化一个Dog对象
        Dog dog = new Dog();
    }
}

注:构造器不可以显示调用(用类名调用),构造器在创建对象时被配调用。


2.5 this关键字


  • 代表当前对象 (可以获取当前类的属性和方法)。
  • 用于区分局部变量和成员变量。
  • this([参数列表]);用来调用本类的构造器。
  • 如果this([参数列表]);在构造中必须是第一条语句。

**[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C7lF58Zv-1656677024324)(Java面向对象.assets/image-20220622155702898.png)]**


2.6 访问权限修饰符


访问级别访问权限修饰符同类同包子类全局范围内
公开public
受保护的protected
默认default
所有public

访问控制级别由小到大排序:private->default->protected->public。


2.7 封装


面向对象的三大特征:封装、继承、多态。

生活中封装的例子:手机、键盘等等

封装的规则:将类的成员隐藏在类的内部,这样外部程序无法直接访问,只能通过类提供的public方法去访问类中隐藏的成员。

封装的好处:

  • 成员变量:私有化成员变量(private),提供公共的get/set方法,可以提高数据的安全性。
  • 成员方法:将一段可以复用的功能封装到方法中,提高代码的复用性,降低我们的工作量。
public class Product {
    // 私有化属性
    private String name;
    private double price;
 
    /*
        对属性进行封装,get/set
     */
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    // 无参构造器
    public Product() {}

    // 有参构造器
    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }
    
    /**
    * 封装一个方法:用于获取当前日期时间
    */
    public String getDate(){
        // 初始化Date对象
        Date date = new Date();
		return date.toString();
	}
}

2.8 标准的JavaBean


JavaBean:也可以称为实体类,其对象可以用于在程序中封装数据。

标准JavaBean须满足如下书写要求:

  • 成员变量使用private修饰。
  • 提供成员变量对应的 set/get方法。
  • 必须提供一个无参构造器;有参构造器可写可不写。

成员变量和局部变量的区别:

区别成员变量局部变量
类中位置不同类中,方法外方法内
初始化值不同有默认值,无需初始化没有默认值,使用之前需要完成赋值
内存位置不同堆内存栈内存
生命周期不同随着对象的创建而存在,随着对象的消失而消失随着方法的调用而存在,随着方法的运行结束而消失
在所归属的大括号内{}

2.9 final 关键字


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

  • 修饰类:表示该类是最终类,不能被继承。例如 :public final class String{}

  • 修饰方法:表示该方法是最终方法,不能被重写。(因此private方法默认是final型的)

  • 修饰变量:使用前必须被初始化;一旦被初始化,将不能再被改变(常量)。

    例如 final int AGE=18;

  • 如果final修饰的变量是引用类型:那么变量存储的地址值不能发生改变,但是地址指向的对象内容是可以发生变化的。

2.10 枚举


1、枚举类的定义格式:

修饰符 enum 枚举名称{
    枚举的第一行都是罗列枚举类的对象名称,建议全部大写。
}  

例如:

public enum Season {
    // 枚举类的第一行默认都是罗列枚举对象的名称,建议全部大写。
    SPRING,SUMMER,AUTUMN,WINTER;
}

我们通过反编译查看枚举类的代码:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uNihQsJn-1656677024325)(Java面向对象.assets/image-20220627145232803.png)]

  • 枚举类都是继承了枚举类型:java.lang.Enum类。
  • 枚举类都是被final修饰,不能被继承。
  • 枚举类的构造器都是私有的,对外不能创建对象。
  • 枚举类的第一行默认都是罗列枚举对象的名称。
  • 枚举类相当于是多例模式。

2、枚举的作用: 枚举可以做信息标志和分类(缺点:不能表示字面值,表示字面值用常量)


三、Static关键字

  • staitc是静态的意思,可以修饰变量和方法。

  • 在类中静态资源无法直接访问非静态的资源。

  • 在静态方法中不能用this关键字。(因为java中的static是类区域,而this表示当前类的对象,然后static修饰的方法是由类直接调用,不需要创建对象,所以在static里不能用this

  • static修饰的变量和方法不会被JVM自动回收。

  • 静态方法不能被重写。

  • 工具型的方法设计成static。(这样不依赖于某个对象,用类调用即可!)

  • static都会和final配合修饰常量。例如 public static final String USER_NAME=“张三”;

代码块

  • 静态代码块:static {...},随着类加载的时候执行,只执行一次,并且优先于各种代码块以及构造器,用于资源初始化。
  • 普通代码块:{...},是实例代码,依赖具体的对象,在创建对象时执行。

四、继承

4.1 继承的定义

  • Java中用关键字extends表示继承,我们可以让一个类和另一个类建立父子关系。

  • 格式: public Dog extends Animal {}

    • Dog称为子类(也叫派生类),Animal称为父类(也叫基类或超类)。
  • 作用:当子类继承父类后,就可以直接使用父类公有的属性和方法。

在这里插入图片描述


1、使用继承的好处

  • 可以提高代码的复用性。(提取相同的特征)
  • 增强类的功能扩展性。

2、继承设计规范

子类中相同的特征(共性属性和共性方法) 放在父类中定义,子类独有的属性和行为应该定义在子类自己里面。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Ej5Zit8-1656677024326)(Java面向对象.assets/image-20220626161039897.png)]

先调用父类的无参构造器初始化父类数据,然后调用子类构造器(无参/有参),对象空间中先划分父类实例变量的内存,然后再划分子类实例变量内存,配合Java中单继承的约束 就可以保障每个类型的变量位置是固定不变的。


3、继承的特点

  • 子类拥有父类非private关键字修饰的属性和方法,但是子类不能继承父类的构造器。
  • Java中只能单继承,一个类只能继承一个父类。
  • Java不支持多继承、但是支持多层继承。
  • 子类可以扩展父类,拥有自己的属性和方法。
  • 子类可以用自己的方式实现父类的方法。(重写方法)
  • Java中所有的类都是Object类的子类。

4.2 方法重写

1、为什么需要重写?

父类的功能,子类不一定需要,或者功能不一定满足。(子类重写父类非static、private修饰的方法)

2、方法重写注意事项:

  • 需要有继承关系,子类重写父类的方法。

  • 方法名必须相同。

  • 参数列表必须相同。

  • 修饰符:范围可以扩大但不能缩小: public>protected>default>private。

  • 抛出的异常:范围可以被缩小但不能扩大 ClassNotFoundException–>Exception(大的)。

  • 方法重写,子类方法和父类方法必须一致,只是方法体不同。

3、方法重载和方法重写的区别

方法重载方法重写
overleadoverride
访问权限修饰符、返回值、异常无关访问权限修饰符、异常、返回值有关
参数列表不同方法名、参数列表相同
发生在同一个类不同类

4.3 super关键字


  • 可以在类中引用父类的属性和方法。
  • 使用 super([参数列表]);来调用父类的构造器。
thissuper
指代当前对象代表父类对象的引用
调用本类的构造器或方法和属性调用父类的构造器或方法和属性
在构造器中必须是第一条语句在子类构造器中必须是第一条语句

五、抽象类

  • abstract 关键字 可以用来修饰方法也可以修饰类,如果修饰方法,那么该方法就是抽象方法;如果修饰类,那么该类就是抽象类。
修饰符 abstract class 类名{
    修饰符 abstract 返回值类型 方法名(形参列表);
}
  • 抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类。
  • 抽象类,不能使用new关键字来创建对象,它是用来让子类继承的。
  • 抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的。
  • 子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类;

示例:

// 抽象类 abstract class 
public abstract class Action {
    /**
     * 抽象方法
     * 它没有方法体,它是一种约定,让别人来实现
     */
    public abstract void doSth();

    // 普通方法
    public void run(){
        System.out.println("小明在奔跑");
    }
}
// 子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类
class A extends Action{
    
    @Override
    public void doSth() {
        System.out.println("小明在唱歌");
    }
}

六、接口

JDK7以前:接口中只能放常量、抽象方法。

JDK8之后的版本:接口可以放常量、抽象方法、默认方法、静态方法。

  • 使用interface关键字声明接口。例如: public interface UserDao{}

  • 接口可以多实现(implement)和多继承(extends)

  • 如果一个类实现了一个或多个接口,就必须重写接口中的所有抽象方法。(大概率的情况下:写接口、写实现类)

  • 接口中所有的抽象方法可以省略 public abstract

  • 接口中所有的变量都是常量,public static final,可以省略不写。

  • 常量的命名规则:所有单词的字母全大写,中间以下划线分割。如STUDENT_STATUS

  • 接口不能被实例化,因为接口中没有构造器。

示例:

// 接口
public interface MyInterface {
    // 抽象方法
    void add();
    void delete();
    void update();
    void select();
}
// 实现接口,重写接口中的所有抽象方法
public class Application implements MyInterface{
    @Override
    public void add() {
        System.out.println("添加");
    }

    @Override
    public void delete() {
        System.out.println("删除");
    }

    @Override
    public void update() {
        System.out.println("修改");
    }

    @Override
    public void select() {
        System.out.println("查询");
    }
}

抽象类和接口的区别:

区别抽象类接口
关键字abstractinterface
成员变量可以包含任意成员变量(包括各种访问级别的类成员变量和实例变量)只能包含公开的静态常量(默认由 public static final 修饰)
方法除了抽象方法外还可以包含任意的方法(包括各种访问级别的类方法和实例方法 )只能包含公开的抽象方法(默认由 public abstract 修饰)
使用抽象类只能被继承(关键字extends),单继承接口可以被实现(关键字implements)和继承

七、多态

多态指的是父类的某个方法被其子类重写时,可以各自产生各自的行为特征。

在这里插入图片描述

多态存在的三个必要条件:继承关系,重写方法,父类引用指向子类对象(向上转型) 。

示例:

//定义一个动物类作为父类
class Animal{
	public void move() {
		System.out.println("动物在移动!");
	}
}

class Fish extends Animal{
	// 重写了父类中的move方法
	public void move() {
		System.out.println("鱼儿在游!");
	}
}

class Bird extends Animal{
	// 重写了父类中的move方法
	public void move() {
		System.out.println("鸟儿在飞!");
	}
}

class Horse extends Animal{
	// 重写了父类中的move方法
	public void move() {
		System.out.println("马儿在跑!");
	}
}


public class Application1 {

	public static void main(String[] args) {
		// 父类引用指向子类对象(向上转型)
		Animal a1 = new Bird();
		Animal a2 = new Fish();
		Animal a3 = new Horse();
	
		a1.move(); // 调用了Bird类的move方法 ,输出:鸟儿在飞!
		a2.move(); // 调用了Fish类的move方法 ,输出:鱼儿在游!
		a3.move(); // 调用了Horse类的move方法,输出:马儿在跑!
	}
}
  • 使用父类引用指向子类对象,该引用只能调用父类中定义的方法和属性。(自动类型转换)
  • 如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法。
  • 父类对象指向子类引用,可以调用子类独有的功能。
  • 多态是指方法的多态,属性没有多态。
  • 使用instanceof关键字判断这个对象是否属于某个类。

八、String、StringBuffer、StringBulider

  • java.lang.String类 代表字符串属于引用数据类型。
  • 在Java中用双引号 “” 括起来的字面量都是String对象。例如 “你好世界”、"apple"等等
  • Java中规定,字符串在创建之后不能改变 (因为它用final修饰的字符数组来存储数据),但是它们可以被共享。(每次拼接字符串,都是在常量池中创建新的字符串)
  • 双引号括起来的字符串,例如:“abc”,“hello” 都是直接存储在方法区的 字符串常量池 当中。
  • 为什么字符串要存储在方法区的字符串常量池中?
    • 因为字符串在实际开发中使用太频繁,为了执行效率,所以把字符串放到了方法区的字符串常量池当中。
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XYwZIxiH-1656677024327)(Java面向对象.assets/image-20220622211011053.png)]

8.1 创建字符串对象


public class StringTest {
    public static void main(String[] args) {
        // 这两行代码表示底层创建了3个字符串对象,都在字符串常量池中
        String s1 = "abc";
        String s2 = "abc"+"def";

        // 使用new的方式创建字符串对象
        // 分析:这里的"def"是从哪里来的?
        // 凡是双引号括起来的都在字符串常量池中有一份。
        // new对象的时候一定在堆当中开辟空间。
        String s3 = new String("def");

    }
}

内存分配图如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9uufh60S-1656677024328)(Java面向对象.assets/image-20220623082551303.png)]


8.2 字符串的比较


== 比较的是两个字符串对象。

String类中的equals()方法,比较存储在两个字符串对象中的内容是否相等。

equalsIgnoreCase()方法,忽略大小写比较字符串。

public class StringTest {
    public static void main(String[] args) {
        String s1 = "一起学Java";
        String s2 = "一起学Java";
        String s3 = "aaa";
        // ==双等号比较的是内存地址
        System.out.println(s1 == s2); // true
        System.out.println(s2 == s3); // false
     
     	String x = new String("hello");
        String y = new String("hello");
        System.out.println(x == y); // false

		String z = null;
        System.out.println("password".equals(z));//false,这种写法避免空指针异常
        System.out.println(z.equals("password")); //NullPointerException
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I21yn7GW-1656677024331)(Java面向对象.assets/image-20220623090906233.png)]

源码分析:

思路:比较地址->比较长度->比较每一个字符。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JxMQE0LK-1656677024332)(Java面向对象.assets/image-20220623084228650.png)]

8.3 String类的构造方法


方法说明
String()创建一个空字符串
String(byte[] bytes)根据字节数组构建一个字符串
String(char[] chars)根据字符数组构建一个字符串
String(String str)复制一个字符串
String(StringBuffer buffer)根据字符缓冲区构建字符串
String(StringBulider bulider)根据字符缓冲区构建字符串

使用最多的方式:接使用字面值的方式创建字符串,如:String str = “hello world”。


8.4 String类常用方法


  • int length(),返回字符串的长度;

  • 返回下标:int indexOf(int ch), 返回指定数字在此字符串中的位置(下标);

  • int indexOf(int ch, int fromIndex),返回指定数字在此字符串中的位置,从指定位置开始查找;

  • int indexOf(String str) ,返回指定子字符在此字符串中的位置;

  • int indexOf(String str,int fromIndex) ,返回指定子字符在此字符串中的位置,从指定位置开始查找;

  • 返回字符: char charAt(int index),返回字符串中指定位置的字符;

  • int lastIndexOf(int ch),返回指定字符在此字符串中最后一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1;

  • int lastIndexOf(int ch, int fromIndex),返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索,如果此字符串中没有这样的字符,则返回 -1;

  • int lastIndexOf(String str),返回指定子字符串在此字符串中最右边出现处的索引,如果此字符串中没有这样的字符,则返回 -1;

  • int lastIndexOf(String str, int fromIndex),返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索,如果此字符串中没有这样的字符,则返回 -1;

  • String trim(),返回一个新字符串,这个字符串将删除原有字符串前后的半角空白字符(占一个字节,unicode编码为\u0020);

  • String strip(),返回一个新字符串,这个字符串将删除原有字符串前后的全角和半角空白字符(占两个字节,unicode编码为\u3000);

  • bollean isEmpty(),判断字符串是否为空;

  • 分割字符串: String[] split(String regex),返回一个字符串数组,根据匹配给定的正则表达式来拆分字符串;

  • String toLowerCase(),返回新一个字符串,这个字符串将原始字符串中的大写字母改为小写;

  • String toUpperCase(),返回新一个字符串,这个字符串将原始字符串中的小写字母改为大写;

  • 截取字符串: String substring(int beginIndex),返回新一个字符串,这个字符串包含原始字符串中从beginIndex(起始索引)到字符串的末尾的所有代码单元;(包括起始位置)

  • String substring(int beginIndex, int endIndex),返回新一个字符串,这个字符串包含原始字符串中从beginIndex(起始索引)到字符串的endIndex-1的所有代码单元。(包括起始位置,不包括结尾位置)

  • 替换字符串: String replace(char searchChar, char newChar),返回一个新字符串,用 newChar 字符替换原始字符串中出现的所有 searchChar 字符;

  • 判断当前字符串是否包含指定的字符:boolean contains(CharSequence s)

  • 字符串转字符数组:char[] toCharArray()

  • 判断字符串以什么字符开始:boolean startsWith(String prefix)

JDK1.8 API在线文档:https://www.matools.com/api/java8


8.5 String练习


1、验证码

需求:随机生成一个5位的验证码,每位可能是数字、大写字母、小写字母。

分析:

  • 定义一个字符串:存储a-zA-Z0-9之间的全部字符。
  • 总共循环5次,每次获取随机范围内的索引,并将获取的字符拼接起来。
public class CaptchaTest {
    public static void main(String[] args) {
        String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

        Random r = new Random();
        String code = "";
        for (int i = 0; i < 5; i++) {
            int index = r.nextInt(str.length());
            char c = str.charAt(index);
            code += c;
        }
        System.out.println(code); //aW2nF
    }
}

2、模拟用户登录

需求:对用户登录进行校验,最多给3次机会。

public class LoginTest {
    public static void main(String[] args) {
        String okLoginName = "root";
        String okPassword = "123456";

        Scanner sc = new Scanner(System.in);
        for (int i = 1; i <= 3 ; i++) {
            System.out.println("用户名:");
            String name = sc.next();
            System.out.println("密码:");
            String pwd = sc.next();
            if (name.equals(okLoginName)&&pwd.equals(okPassword)){
                System.out.println("登录成功");
                break;
            }else {
                System.out.println(" 账号或密码错误 , 你还有"+(3-i)+"次机会!");
            }
        }

    }
}

3、手机号码屏蔽

需求:接收一个11位的手机号,将中间四位号码屏蔽。例如:139* * * *59803

public class TelphoneTest {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个11位的号码:");
        String tel = sc.next();

        // 获取前三位号码
        String befor = tel.substring(0, 3); // [0,3)
        // 获取后四位号码
        String after = tel.substring(7); //从头截到尾

        tel = befor + "****" + after;
        System.out.println("屏蔽之后的手机号码为:"+tel);
    }
}

8.6 StringBuffer


  • StringBuffer 是一个字符串缓冲区,内容是可变的。
  • 支持链式编程。
  • 它是线程安全的 (StringBulider在单线程环境下效率更高)。
  • 作用:提高字符串的操作效率,如拼接、修改等等。
  • StringBuffer 与 String 是可以转换的。
  • StringBuffer - > String : buffer.toString()。
  • String - > StringBuffer : StringBuffer buffer = new StringBuffer(string)。

StringBuffer的构造方法

构造方法说明
public StringBuffer()构造一个不带字符的字符串缓冲区,保留16个字符的空间。
public StringBuffer(int[] capacity)构建一个不带字符,但具有指定初始容量的字符串缓冲区。
public StringBuffer(String str)构建一个字符串缓冲区,并将其内容初始化为指定的字符串内容。(初始容量为:16+参数str的长度)

StringBuffer常用方法

方法说明
append(String str)用来在字符串末尾连接一个新的字符串str
insert(int offest,String sub)在指定位置插入字符串sub。
delete(int beginIndex,int endIndex)用于删除从beginIndex开始到endIndex结束之间的字符串(含beginIndex,不包含 endindex)
reverse()把StringBuffer内存反转
toString()把StirngBuffer变成String
replace(int start,int end,String str)使用给定String中的字符替换此字符序列的字符串中的字符
length()返回StringBuffer的长度
public class TestStringBuffer {
    public static void main(String[] args) {
        // 创建一个StringBuffer对象
        StringBuffer buffer = new StringBuffer("你不要留在过去");
        // 向尾部追加数据
        buffer.append(",");
        buffer.append("因为明天一定会到来").append("。");//链式编程
        System.out.println(buffer);
    }
}

8.7 StringBulider


与 StringBuffer 基本相同,只是线程不安全(执行效率高)。

小结

  • String 是 Java 中基础且重要的类,被声明为 final class,是不可变字符串。因为它的不可变性,所以拼接字符串时候会产生很多无用的中间对象,如果频繁的进行这样的操作对性能有所影响。
  • StringBuffer 就是为了解决大量拼接字符串时产生很多中间对象问题而提供的一个类。它提供了 append()方法,可以将字符串添加到已有序列的末尾或指定位置,它的本质是一个线程安全的可修改的字符序列。
  • 在很多情况下我们的字符串拼接操作不需要线程安全,所以 StringBuilder 登场了。StringBuilder 是 JDK1.5 发布的,它和 StringBuffer 本质上没什么区别,就是去掉了保证线程安全的那部分,减少了开销。
  • 线程安全: StringBuffer线程安全,StringBuilder线程不安全。
  • 速度:一般情况下,速度从快到慢为 StringBuilder > StringBuffer > String,当然这是相对的,不是绝对的。
  • 使用场景:
    • 操作少量的数据使用 String。
    • 单线程操作大量数据使用 StringBuilder。
    • 多线程操作大量数据使用 StringBuffer。

8.8 StringJoiner


JDK8出现的,简化字符串的拼接,使用的人很少。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LIoH7gSU-1656677024333)(Java面向对象.assets/image-20220627162553555.png)]


九、内部类

将一个类定义在另一个类里面或者方法里面,这样的类就被称作内部类。

内部类可以分为四种:成员内部类、局部内部类、静态内部类、匿名内部类(重点)。

1、成员内部类

class Outer {
    private int num = 10;
    
    public void out() {
        System.out.println("这是外部的方法");
    }

    class Inner {
        public void in() {
            System.out.println("这是内部的方法");
        }

        public void getNum() {
            System.out.println(num);
        }
    }
}

public class Test2 {
    public static void main(String[] args) {
        Outer outer = new Outer();
        //通过外部类来实例化内部类
        Outer.Inner inner = outer.new Inner();
        inner.in();
        inner.getNum();
    }
}

在这里插入图片描述


2、局部内部类

class Outer1 {
    //局部内部类
    public void method() {
        class Inner {
            public void in() {
                System.out.println("我是局部内部类");
            }
        }
        new Inner().in();
    }
}

public class Test3 {
    public static void main(String[] args) {
        Outer1 outer1 = new Outer1();
        outer1.method();
    }
}

在这里插入图片描述


3、静态内部类

class Outer2{
    private int num = 100;
    public void out(){
        System.out.println("我是外部类");
    }

    //静态成员内部类
    static class Inner2{
        public void in(){
            System.out.println("我是内部类");
        }
    }
}

public class Test4 {
    public static void main(String[] args) {
        Outer2 outer2 = new Outer2();
        outer2.out();
		
        //创建对象格式:外部类名.内部类名 对象名=new外部类名.内部类构造器;
        Outer2.Inner2 inner2 = new Outer2.Inner2();
        inner2.in();
    }
}


4、匿名内部类

class Xxx {
    public void shout() {
        System.out.println("嗷~");
    }
}

interface UserService {
    void hello();
}

public class Test5 {
    public static void main(String[] args) {
        //匿名对象.方法
        new Xxx().shout();

        // 适合那种只需要使用一次的类。比如:键盘监听操作等等。
        new UserService() {
            @Override
            public void hello() {
                System.out.println("hello");
            }
        }.hello();
    }
}


十、集合框架

👉点我跳转


十一、常用的API

👉点我跳转

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
封装是面向对象编程中的一个重要概念,它主要是指将数据和行为封装在一起,形成一个类,并对外提供接口,隐藏实现细节,保证数据安全性和代码可维护性。 Python中的封装主要通过访问权限控制实现。在Python中,属性和方法都有其对应的访问权限,主要有公有、私有和受保护三种。 公有属性和方法可以被类内部和外部访问,私有属性和方法只能在类内部访问,受保护属性和方法也只能在类内部和子类中访问。 下面通过一个例子来说明Python中如何进行封装。 ```python class Person: def __init__(self, name, age): self.__name = name # 私有属性 self.__age = age # 私有属性 def say_hello(self): print("Hello, my name is %s, and I'm %d years old." % (self.__name, self.__age)) def set_age(self, age): if age < 0 or age > 150: print("Invalid age!") else: self.__age = age # 修改私有属性 p = Person("Tom", 20) p.say_hello() # 输出:Hello, my name is Tom, and I'm 20 years old. p.__name # 报错:AttributeError: 'Person' object has no attribute '__name' p.set_age(200) # 输出:Invalid age! ``` 在上面的例子中,我们定义了一个Person类,其中包含了两个私有属性__name和__age,以及一个公有方法say_hello和一个受保护方法set_age。这样,外部就无法直接访问__name和__age属性,只能通过调用say_hello方法来输出实例的信息。同时,set_age方法可以修改私有属性__age,但是它会对输入的年龄进行检查,保证数据的合法性。 可以看出,Python中的封装通过访问权限控制实现,可以保证数据的安全性和代码的可维护性。在实际开发中,我们应该尽量使用封装来保护数据,防止出现意外错误。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白豆五

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值