Java作为一种面向对象语言。支持以下基本概念:

  • 多态
  • 继承
  • 封装
  • 抽象
  • 对象
  • 实例
  • 方法
  • 重载

第一节 类与对象

本节我们重点研究对象和类的概念。

  • 对象:对象是类的一个实例(对象不是找个女朋友),有状态和行为。
  • 例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。
  • :类是一个模板,它描述一类对象的行为和状态。

下图中男孩(boy)女孩(girl)类(class),而具体的每个人为该类的对象(object)

【添油加醋的Java基础】第四章 面向对象程序设计_夏明亮

下图中汽车类(class),而具体的每辆车为该汽车类的对象(object),对象包含了汽车的颜色、品牌、名称等。

【添油加醋的Java基础】第四章 面向对象程序设计_类_02

Java中的对象

看看周围真实的世界,会发现身边有很多对象,车,狗,人等等。所有这些对象都有自己的状态和行为。

拿一条狗来举例,它的状态有:名字、品种、颜色,行为有:叫、摇尾巴和跑。

对比现实对象和软件对象,它们之间十分相似。

软件对象也有状态和行为。软件对象的状态就是属性,行为通过方法体现。

在软件开发中,方法操作对象内部状态的改变,对象的相互调用也是通过方法来完成。

Java 中的类

类可以看成是创建 Java 对象的模板。

【添油加醋的Java基础】第四章 面向对象程序设计_夏明亮_03

通过上图创建一个简单的类来理解下 Java 中类的定义:

public class Dog {
    String breed;
    int size;
    String colour;
    int age;
 
    void eat() {
    }
 
    void run() {
    }
 
    void sleep(){
    }
 
    void name(){
    }
}

一个类可以包含以下类型变量:

  • 局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
  • 成员变量:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。
  • 类变量:类变量也声明在类中,方法体之外,但必须声明为 static 类型。

一个类可以拥有多个方法、多个局部变量、多个成员变量、多个类变量,在上面的例子中:eat()、run()、sleep() 和 name() 都是 Dog 类的方法。

类的构造方法

每个类都有构造方法。如果没有显式地为类定义构造方法,Java 编译器将会为该类提供一个默认构造方法

在创建一个对象的时候,至少要调用一个构造方法。构造方法的名称必须与类同名一个类可以有多个构造方法

下面是一个构造方法示例:

public class Puppy{
    public Puppy(){
    }
 
    public Puppy(String name){
        // 这个构造器仅有一个参数:name
    }
}

创建对象

对象是根据类创建的。在Java中,使用关键字 new 来创建一个新的对象。创建对象需要以下三步:

  • 声明:声明一个对象,包括对象名称和对象类型。
  • 实例化:使用关键字 new 来创建一个对象。
  • 初始化:使用 new 创建对象时,会调用构造方法初始化对象。

下面是一个创建对象的例子:

public class Puppy{
   public Puppy(String name){  // 构造函数
      //这个构造器仅有一个参数:name
      System.out.println("小狗的名字是 : " + name ); 
   }
   public static void main(String[] args){  // main函数
      // 下面的语句将创建一个Puppy对象
      Puppy myPuppy = new Puppy( "tommy" );
   }
}

编译并运行上面的程序,会打印出下面的结果:

小狗的名字是 : tommy

访问实例变量和方法

通过已创建的对象来访问成员变量和成员方法是使用点号,如下所示:

/* 实例化对象 */
Object referenceVariable = new Constructor();
/* 访问类中的变量 */
referenceVariable.variableName;
/* 访问类中的方法 */
referenceVariable.methodName();

使用 Object 类型声明变量只能在编译时访问 Object 类中的方法和属性,但在运行时,你可以通过强制类型转换将其转换为特定类型,以便访问特定类型的方法和属性。

下面的例子展示如何访问实例变量和调用成员方法:

public class Puppy{  // 公共类
   int puppyAge;     // 成员变量
   public Puppy(String name){  // 构造函数
      // 这个构造器仅有一个参数:name
      System.out.println("小狗的名字是 : " + name );   // 标准输出
   }
 
   public void setAge( int age ){  // 没有返回值的public类型的需要一个int类型参数的方法
       puppyAge = age;
   }
 
   public int getAge( ){ // 返回值类型为int的public类型的无参数方法
       System.out.println("小狗的年龄为 : " + puppyAge ); 
       return puppyAge;  // 返回值
   }
 
   public static void main(String[] args){  // 程序入口,main()函数
      /* 创建对象 */
      Puppy myPuppy = new Puppy( "tommy" );
      /* 通过方法来设定age */
      myPuppy.setAge( 2 );
      /* 调用另一个方法获取age */
      myPuppy.getAge( );
      /*你也可以像下面这样访问成员变量 */
      System.out.println("变量值 : " + myPuppy.puppyAge ); 
   }
}

编译并运行上面的程序,产生如下结果:

小狗的名字是 : tommy
小狗的年龄为 : 2
变量值 : 2

“对象”(Object)VS. “实例”(Instance)

在 Java 中,“对象”(Object)和“实例”(Instance)通常指的是同一个概念,尽管在某些上下文中它们可能有细微的区别。让我们详细讨论一下这两个术语及其异同。

对象(Object)

  • 定义:对象是类的一个具体实现,表示一个特定的实体或事物。对象是类的实例化结果,包含类的属性(字段)和行为(方法)。
  • 特点
  • 在内存中分配空间。
  • 具有状态(属性值)和行为(方法)。
  • 通过构造方法进行初始化。

实例(Instance)

  • 定义:实例是类的一个具体对象。实例是一个对象,表示该类在内存中的一个具体实现。
  • 特点
  • 与对象基本相同,通常用来强调具体的一个对象属于某个类。
  • 强调类被实例化的过程和结果。

异同点

  • 相同点
  • 在大多数情况下,对象和实例可以互换使用,表示类的一个具体实现。
  • 都是通过类的构造方法创建的。
  • 在内存中表示类的一个具体存在。
  • 不同点
  • “对象”更多地用于描述内存中存在的实体。
  • “实例”更多地用于描述创建对象的过程和结果,以及对象与其类之间的关系。

让我们通过一个示例来说明对象和实例的概念:

public class Car {
    // 属性
    private String brand;
    private String model;
    
    // 构造方法
    public Car(String brand, String model) {
        this.brand = brand;
        this.model = model;
    }
    
    // 方法
    public void drive() {
        System.out.println("Driving " + brand + " " + model);
    }
    
    public static void main(String[] args) {
        // 创建对象/实例
        Car myCar = new Car("Toyota", "Corolla");
        
        // myCar 是 Car 类的一个对象
        // myCar 也是 Car 类的一个实例
        
        // 调用方法
        myCar.drive();
    }
}

在上述示例中:

  • myCarCar 类的一个对象。
  • myCar 也是 Car 类的一个实例。

这里,“对象”和“实例”可以互换使用,因为它们表示的是 Car 类的一个具体实现。

在 Java 编程中,“对象”和“实例”通常被视为同义词,都是指通过类创建的具体实现。对象强调的是内存中的实体,实例则更多地强调类被实例化的过程和结果。在绝大多数情况下,开发者可以互换使用这两个术语而不会引起混淆。

第二节 定义方法

在前面几个章节中我们经常使用到 System.out.println(),那么它是什么呢?

  • println() 是一个方法。
  • System 是系统类。
  • out 是标准输出对象。

这句话的用法是调用系统类 System 中的标准输出对象 out 中的方法 println()。

那么什么是方法呢?

Java方法是语句的集合,它们在一起执行一个功能。

  • 方法是解决一类问题的步骤的有序组合
  • 方法包含于类或对象中
  • 方法在程序中被创建,在其他地方被引用

方法的优点

  • 使程序变得更简短而清晰。
  • 有利于程序维护。
  • 可以提高程序开发的效率。
  • 提高了代码的重用性。

方法的命名规则

  • 方法的名字的第一个单词应以小写字母作为开头,后面的单词则用大写字母开头写,不使用连接符。例如:addPerson
  • 下划线可能出现在 JUnit 测试方法名称中用以分隔名称的逻辑组件。一个典型的模式是:test<MethodUnderTest>_<state>,例如 testPop_emptyStack

方法的定义

一般情况下,定义一个方法包含以下语法:

修饰符 返回值类型 方法名(参数类型 参数名){
    ...
    方法体
    ...
    return 返回值;
}

方法包含一个方法头和一个方法体。下面是一个方法的所有部分:

  • 修饰符:修饰符,这是可选的,告诉编译器如何调用该方法。定义了该方法的访问类型。
  • 返回值类型 :方法可能会返回值。returnValueType 是方法返回值的数据类型。有些方法执行所需的操作,但没有返回值。在这种情况下,returnValueType 是关键字void
  • 方法名:是方法的实际名称。方法名和参数表共同构成方法签名。
  • 参数类型:参数像是一个占位符。当方法被调用时,传递值给参数。这个值被称为实参或变量。参数列表是指方法的参数类型、顺序和参数的个数。参数是可选的,方法可以不包含任何参数。
  • 方法体:方法体包含具体的语句,定义该方法的功能。

【添油加醋的Java基础】第四章 面向对象程序设计_对象_04

注意: 在一些其它语言中方法指过程和函数。一个返回非void类型返回值的方法称为函数;一个返回void类型返回值的方法叫做过程。

方法调用

Java 支持两种调用方法的方式,根据方法是否返回值来选择。

当程序调用一个方法时,程序的控制权交给了被调用的方法。当被调用方法的返回语句执行或者到达方法体闭括号时候交还控制权给程序。

当方法返回一个值的时候,方法调用通常被当做一个值。例如:

int larger = max(30, 40);

如果方法返回值是void,方法调用一定是一条语句。例如,方法println返回void。下面的调用是个语句:

System.out.println("Hello World!");

例子:

public class TestMax {
   /** 主方法 */
   public static void main(String[] args) {
      int i = 5;
      int j = 2;
      int k = max(i, j);
      System.out.println( i + " 和 " + j + " 比较,最大值是:" + k);
   }
 
   /** 返回两个整数变量较大的值 */
   public static int max(int num1, int num2) {
      int result;
      if (num1 > num2)
         result = num1;
      else
         result = num2;
 
      return result; 
   }
}

这个程序包含 main 方法和 max 方法。main 方法是被 JVM 调用的,除此之外,main 方法和其它方法没什么区别。

main 方法的头部是不变的,如例子所示,带修饰符 public 和 static,返回 void 类型值,方法名字是 main,此外带个一个 String[] 类型参数。String[] 表明参数是字符串数组。

void 关键字

本节说明如何声明和调用一个 void 方法。

下面的例子声明了一个名为 printGrade 的方法,并且调用它来打印给定的分数。

示例:

public class TestVoidMethod {
  public static void main(String[] args) {
    printGrade(78.5);
  }
 
  public static void printGrade(double score) {
    if (score >= 90.0) {
       System.out.println('A');
    }
    else if (score >= 80.0) {
       System.out.println('B');
    }
    else if (score >= 70.0) {
       System.out.println('C');
    }
    else if (score >= 60.0) {
       System.out.println('D');
    }
    else {
       System.out.println('F');
    }
  }
}

以上实例编译运行结果如下:

C

这里printGrade方法是一个void类型方法,它不返回值。

一个void方法的调用一定是一个语句。 所以,它被在main方法第三行以语句形式调用。就像任何以分号结束的语句一样。

方法的重载

方法重载(Method Overloading)是Java中的一种多态性表现,允许在同一个类中定义多个方法,这些方法具有相同的名称但具有不同的参数列表(参数的类型、个数或顺序不同)。方法重载提高了程序的可读性和灵活性。

规则

  1. 方法名称相同:重载的方法必须具有相同的名称。
  2. 参数列表不同:重载的方法必须有不同的参数列表(参数类型、个数或顺序不同)。
  3. 返回类型可以不同:虽然重载方法的返回类型可以不同,但仅靠返回类型的不同无法实现方法重载。
  4. 修饰符可以不同:重载方法的访问修饰符可以不同。

示例

public class MethodOverloadingExample {

    // 重载方法:参数个数不同
    public int add(int a, int b) {
        return a + b;
    }

    // 重载方法:参数类型不同
    public double add(double a, double b) {
        return a + b;
    }

    // 重载方法:参数个数和类型不同
    public int add(int a, int b, int c) {
        return a + b + c;
    }

    // 重载方法:参数顺序不同
    public String concatenate(String a, int b) {
        return a + b;
    }

    // 重载方法:参数顺序不同
    public String concatenate(int a, String b) {
        return a + b;
    }

    public static void main(String[] args) {
        MethodOverloadingExample example = new MethodOverloadingExample();
        
        System.out.println(example.add(1, 2));           // 调用 add(int, int)
        System.out.println(example.add(1.5, 2.5));       // 调用 add(double, double)
        System.out.println(example.add(1, 2, 3));        // 调用 add(int, int, int)
        System.out.println(example.concatenate("Hello", 42)); // 调用 concatenate(String, int)
        System.out.println(example.concatenate(42, "Hello")); // 调用 concatenate(int, String)
    }
}

注意事项

  • 参数的类型、个数或顺序:方法重载的关键在于参数列表的不同。仅仅依靠返回类型的不同无法实现方法重载。
  • 自动类型转换:在调用重载方法时,Java编译器会根据传递的参数类型自动选择最匹配的方法。如果没有完全匹配的方法,编译器会尝试通过自动类型转换找到合适的方法。

自动类型转换示例

public class AutomaticTypeConversion {

    public void print(int a) {
        System.out.println("Printing int: " + a);
    }

    public void print(double a) {
        System.out.println("Printing double: " + a);
    }

    public static void main(String[] args) {
        AutomaticTypeConversion example = new AutomaticTypeConversion();
        
        example.print(10);     // 调用 print(int)
        example.print(10.5);   // 调用 print(double)
        example.print('A');    // 调用 print(int) ('A' 自动转换为对应的 ASCII 码)
    }
}

重载的好处

  • 提高代码的可读性:使用同一个方法名称可以使代码更具可读性,因为方法的用途是一致的,只是参数不同。
  • 提高代码的灵活性:允许对同一个方法进行不同的实现,适应不同的参数需求。

方法重载是Java中的一种多态性表现,通过重载可以在同一个类中定义多个名称相同但参数不同的方法,从而提高代码的可读性和灵活性。理解方法重载的规则和应用场景,有助于编写更简洁、清晰和灵活的代码。

变量作用域

变量的范围是程序中该变量可以被引用的部分。

方法内定义的变量被称为局部变量。

局部变量的作用范围从声明开始,直到包含它的块结束。

局部变量必须声明才可以使用。

方法的参数范围涵盖整个方法。参数实际上是一个局部变量。

for循环的初始化部分声明的变量,其作用范围在整个循环。

但循环体内声明的变量其适用范围是从它声明到循环体结束。它包含如下所示的变量声明:

【添油加醋的Java基础】第四章 面向对象程序设计_类_05

你可以在一个方法里,不同的非嵌套块中多次声明一个具有相同的名称局部变量,但你不能在嵌套块内两次声明局部变量。

命令行参数的使用

有时候你希望运行一个程序时候再传递给它消息。这要靠传递命令行参数给main()函数实现。

命令行参数是在执行程序时候紧跟在程序名字后面的信息。

实例

下面的程序打印所有的命令行参数:

public class CommandLine {
   public static void main(String[] args){ 
      for(int i=0; i<args.length; i++){
         System.out.println("args[" + i + "]: " + args[i]);
      }
   }
}

如下所示,运行这个程序:

$ javac CommandLine.java 
$ java CommandLine this is a command line 200 -100
args[0]: this
args[1]: is
args[2]: a
args[3]: command
args[4]: line
args[5]: 200
args[6]: -100

构造方法

当一个对象被创建时候,构造方法用来初始化该对象。构造方法和它所在类的名字相同,但构造方法没有返回值。

通常会使用构造方法给一个类的实例变量赋初值,或者执行其它必要的步骤来创建一个完整的对象。

不管你是否自定义构造方法,所有的类都有构造方法,因为 Java 自动提供了一个默认构造方法,默认构造方法的访问修饰符和类的访问修饰符相同(类为 public,构造函数也为 public;类改为 protected,构造函数也改为 protected)。

一旦你定义了自己的构造方法,默认构造方法就会失效。

例子1:无参数

下面是一个使用构造方法的例子:

// 一个简单的构造函数
class MyClass {
  int x;
 
  // 以下是构造函数
  MyClass() {
    x = 10;
  }
}

使用:

public class ConsDemo {
   public static void main(String[] args) {
      MyClass t1 = new MyClass();
      MyClass t2 = new MyClass();
      System.out.println(t1.x + " " + t2.x);
   }
}

例子2:有参数

定义:

// 一个简单的构造函数
class MyClass {
  int x;
 
  // 以下是构造函数
  MyClass(int i ) {  // 有参数
    x = i;
  }
}

使用:

public class ConsDemo {
  public static void main(String[] args) {
    MyClass t1 = new MyClass( 10 );
    MyClass t2 = new MyClass( 20 );
    System.out.println(t1.x + " " + t2.x);  // 10 20
  }
}

可变参数

JDK 1.5 开始,Java支持传递同类型的可变参数给一个方法。

方法的可变参数的声明如下所示:

typeName... parameterName

在方法声明中,在指定参数类型后加一个省略号(...) 。

一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明。

例子3:可变参数

定义:

public class VarargsDemo {
    public static void main(String[] args) {
        // 调用可变参数的方法
        printMax(34, 3, 3, 2, 56.5);
        printMax(new double[]{1, 2, 3});
    }
 
    public static void printMax( double... numbers) { // 可变参数
        if (numbers.length == 0) {
            System.out.println("No argument passed");
            return;
        }
 
        double result = numbers[0];
 
        for (int i = 1; i <  numbers.length; i++){
            if (numbers[i] >  result) {
                result = numbers[i];
            }
        }
        System.out.println("The max value is " + result);
    }
}

以上实例编译运行结果如下:

The max value is 56.5
The max value is 3.0

finalize() 方法

Java 中没有像 C++ 那样的析构函数。

Java 允许定义这样的方法,它在对象被垃圾收集器析构(回收)之前调用,这个方法叫做 finalize( ),它用来清除回收对象。

例如,你可以使用 finalize() 来确保一个对象打开的文件被关闭了。

在 finalize() 方法里,你必须指定在对象销毁时候要执行的操作。

finalize() 一般格式是:

protected void finalize()
 {
    // 在这里终结代码
 }

finalize 方法的缺点

  1. 不确定性:垃圾回收器不保证会及时调用 finalize 方法,也不保证在程序终止前一定会调用 finalize 方法。
  2. 性能问题:使用 finalize 方法会影响垃圾回收的性能,因为增加了垃圾回收的复杂性和开销。
  3. 替代方法:更好的资源管理方式是使用显式的资源清理方法,如 close 方法,结合 try-with-resources 语法或显式调用。

第三节 静态成员

在Java中,静态成员(static members)包括静态变量(static variables)和静态方法(static methods)。

静态成员与类本身相关,而不是与类的实例相关。

注意:Static是不能用来修饰类的,也就是不存在静态类的说法。

静态变量

定义: 静态变量是属于类的,而不是类的某个实例的变量。它们在类的所有实例之间共享。

特点

  1. 共享变量:所有实例共享同一个静态变量。
  2. 类加载时初始化:静态变量在类加载时初始化。
  3. 通过类名访问:可以通过类名直接访问静态变量,也可以通过实例访问,但不推荐
  4. 生命周期:静态变量的生命周期与类的生命周期一致。

例子:

public class Counter {
     public static int count = 0;    // 静态变量,使用static关键字标识
 
     public Counter() {
         count++;
     }
 
     public static void main(String[] args) {    // 静态方法,同样使用static关键字标识
         Counter c1 = new Counter();
         Counter c2 = new Counter();
         Counter c3 = new Counter();
         System.out.println("Number of instances: " + Counter.count); // 输出:Number of instances: 3
     }
 }

静态方法

定义: 静态方法是属于类的,而不是类的某个实例的方法。它们可以直接通过类名调用,而不需要创建类的实例。

特点

  1. 无需实例:可以通过类名直接调用。
  2. 不能访问实例变量和实例方法:静态方法不能直接访问类的实例变量和实例方法(也就是不能直接访问和使用类的非静态变量和非静态方法),因为它们不属于任何实例。
  3. 常用于工具类:静态方法通常用于提供不依赖于对象状态的功能,比如数学计算、字符串操作等。

例子:

public class MathUtils {
    public static int add(int a, int b) {
        return a + b;
    }

    public static void main(String[] args) {
        int result = MathUtils.add(5, 3);
        System.out.println("Sum: " + result); // 输出:Sum: 8
    }
}

静态块

定义: 静态块用于初始化类的静态变量。在类加载时执行一次。

特点

  1. 类加载时执行:静态块在类加载时执行一次。
  2. 用于静态变量初始化:可以用于复杂的静态变量初始化。

例子:

public class StaticBlockExample {
    public static int count;

    static {
        count = 10;
        System.out.println("Static block executed");
    }

    public static void main(String[] args) {
        System.out.println("Count: " + StaticBlockExample.count); // 输出:Static block executed \n Count: 10
    }
}

在Java中,static语句块(或静态初始化块)的访问限定符与普通的实例初始化块有所不同。静态初始化块没有显式的访问控制修饰符(如public、private、protected)

虽然静态初始化块没有显式的访问修饰符,但它的可见性和访问控制依赖于它所在的类的访问修饰符。在这个例子中,StaticBlockExample类是public的,所以任何可以访问StaticBlockExample类的代码也可以触发静态初始化块的执行。

总的来说;静态成员在类的所有实例之间共享,这使得它们在需要共享状态或方法的场景中非常有用。静态变量可以用于保存全局状态或计数器,静态方法则通常用于实现工具方法或工厂方法。

第四节 包装类

在 Java 中,包装类(Wrapper Class)是用于将基本数据类型(primitive types)包装成对象的类。Java 提供了一个包装类给每个基本数据类型,以便可以在需要对象而不是基本类型的上下文中使用这些基本类型。包装类提供了许多有用的方法,可以对基本类型进行操作和转换。

基本数据类型和对应的包装类

基本数据类型

包装类

byte

Byte

short

Short

int

Integer

long

Long

float

Float

double

Double

char

Character

boolean

Boolean

为什么需要包装类?

  1. 对象集合
  • Java 集合框架(如 ArrayListHashMap)只能存储对象,而不能存储基本数据类型。使用包装类可以将基本类型转换为对象,从而存储在集合中。
  1. 对象方法
  • 包装类提供了许多方法,可以对基本类型进行操作。例如,将字符串转换为数值、进行数值比较等。
  1. 自动装箱和拆箱
  • 自动装箱(Autoboxing)是将基本类型自动转换为其对应的包装类对象。
  • 自动拆箱(Unboxing)是将包装类对象自动转换为基本类型。
  • 这些特性在 Java 5 之后引入,使得基本类型和对象之间的转换更加方便。

自动装箱和拆箱示例

public class WrapperExample {
    public static void main(String[] args) {
        // 自动装箱:将基本类型 int 转换为包装类 Integer
        int primitiveInt = 5;
        Integer wrappedInt = primitiveInt; // 自动装箱

        // 自动拆箱:将包装类 Integer 转换为基本类型 int
        Integer anotherWrappedInt = new Integer(10);
        int anotherPrimitiveInt = anotherWrappedInt; // 自动拆箱

        // 在集合中使用包装类
        ArrayList<Integer> list = new ArrayList<>();
        list.add(primitiveInt); // 自动装箱

        // 使用包装类提供的方法
        String numberStr = "123";
        int parsedInt = Integer.parseInt(numberStr); // 字符串转换为 int

        System.out.println("Wrapped Integer: " + wrappedInt);
        System.out.println("Another Primitive Int: " + anotherPrimitiveInt);
        System.out.println("Parsed Int: " + parsedInt);
    }
}

包装类的常用方法

  • 转换
  • Integer.parseInt(String s):将字符串转换为 int
  • Double.parseDouble(String s):将字符串转换为 double
  • 比较
  • Integer.compare(int x, int y):比较两个 int 值。
  • Double.compare(double x, double y):比较两个 double 值。
  • 值获取
  • Integer.intValue():获取 Integer 对象的 int 值。
  • Double.doubleValue():获取 Double 对象的 double 值。
  • 常量
  • 包装类提供了一些常量,例如 Integer.MAX_VALUEInteger.MIN_VALUE 分别表示 int 的最大值和最小值。

示例代码:使用包装类方法

public class WrapperMethodsExample {
     public static void main(String[] args) {
         // 字符串转换为 int
         String str = "42";
         int num = Integer.parseInt(str);
         System.out.println("Parsed int: " + num);
 
         // 比较两个 Integer 对象
         Integer a = 100;
         Integer b = 200;
         int comparison = Integer.compare(a, b);
         System.out.println("Comparison result: " + comparison); // 输出 -1,因为 a < b
 
         // 获取 Integer 的最大值和最小值
         int maxInt = Integer.MAX_VALUE;
         int minInt = Integer.MIN_VALUE;
         System.out.println("Max int: " + maxInt);
         System.out.println("Min int: " + minInt);
     }
 }
 

包装类在 Java 中提供了将基本数据类型与对象类型相互转换的功能,并且包装类还提供了许多有用的方法来操作和处理基本类型的数据。在需要对象而不是基本类型的上下文中,包装类是非常有用的工具。通过自动装箱和拆箱的特性,Java 开发者可以更加方便地在基本类型和对象类型之间进行转换。

第五节 封装

在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函数接口的实现细节部分包装、隐藏起来的方法。

封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。

要访问该类的代码和数据,必须通过严格的接口控制。

封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。

适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。

封装的优点

  • 良好的封装能够减少耦合。
  • 类内部的结构可以自由修改。
  • 可以对成员变量进行更精确的控制。
  • 隐藏信息,实现细节。

实现Java封装的步骤

  1. 修改属性的可见性来限制对属性的访问(一般限制为private)
    例如:
public class Person {
     //将 name 和 age 属性设置为私有的,只能本类才能访问,其他类都访问不了,如此就对信息进行了隐藏。
     private String name; 
     private int age;
 }
  1. 对每个值属性提供对外的公共方法访问,也就是创建一对赋取值方法,用于对私有属性的访问
    例如:
public class Person{
     private String name; // 私有
     private int age; // 私有
 
     public int getAge(){ // 公共:读
       return age;
     }
 
     public String getName(){ // 公共:读
       return name;
     }
 
     public void setAge(int age){ // 公共:写
       this.age = age;
       // 采用 this 关键字是为了解决实例变量(private int age)和局部变量(setAge(int age)中的age变量)之间发生的同名的冲突。
     }
     
     public void setName(String name){ // 公共:写
       this.name = name;
     }
 }

实例中public方法是外部类访问该类成员变量的入口。

通常情况下,这些方法被称为getter和setter方法。

因此,任何要访问类中私有成员变量的类都要通过这些getter和setter方法。

本章小结

习题