一.面向对象的概念
1.1什么是面向对象
面向对象是一种计算机编程的范式,它基于现实世界中的对象来构建软件系统。面向对象的核心概念是“对象”,每个对象都拥有数据(属性)和操作这些数据的方法(行为),对象之间通过发送和接收消息来进行通信。
1.2面向对象的特性
面向对象的主要特点包括封装,继承和多态。封装是将数据和操作数据的代码捆绑在一起,形成一个独立的单元;继承是一个类(子类)可以继承另一个类(父类)的属性和方法;多态是指不同的对象可以对同一消息做出响应。
补:面向对象的四大基本特征:封装,多态,继承和抽象。
1.3类与对象
类(Class):类是对象的蓝图或模板,描述了具有相同的属性和方法的对象的集合。
public class MyClass {
// 定义属性(成员变量)
private int myInt;
private String myString;
// 构造方法,用于创建对象时的初始化
public MyClass() {
// 默认初始化
myInt = 0;
myString = null;
}
// 定义方法(成员函数)
public void setMyInt(int value) {
this.myInt = value;
}
public int getMyInt() {
return myInt;
}
public void setMyString(String value) {
this.myString = value;
}
public String getMyString() {
return myString;
}
}
以下是关于Java类定义的一些关键点:
访问修饰符:Java类可以有不同的访问修饰符,如public、private、protected或默认无修饰符。这决定了其他类如何访问该类及其成员。
成员变量:类中的变量称为成员变量或属性。它们定义了对象的状态。在上面的例子中,myInt和myString就是成员变量。
构造方法:构造方法是用于创建类的新实例的特殊方法。它具有与类名相同的名称,并且没有返回类型。在上面的例子中,有一个无参数的构造方法。
方法:类可以包含方法,这些方法定义了类的行为。方法可以带有参数,并可以返回一个值(如果有返回值的话)。在上面的例子中,有四个方法用于设置和获取成员变量的值。
封装:在Java中,封装是一种重要的面向对象编程概念。它意味着将数据(属性)和操作数据的方法绑定在一起,以形成一个独立的对象。通过封装,可以隐藏对象的内部状态和实现细节,只提供公共的接口供外部使用。在上面的例子中,通过将成员变量声明为私有(private),实现了封装。
访问器和方法:为了从外部获取或设置私有成员变量的值,通常需要提供公共的“访问器”方法(也称为getter和setter方法)。在上面的例子中,有四个访问器方法用于获取和设置myInt和myString的值。
对象(Object):对象是类的实例,是类的具体表现形式。每个对象都有相同的属性和行为,但可以有不同的状态。
1.对象的创建与使用
(1)定义类:首先,你需要定义一个类。
public class MyObject {
// 属性(字段)
private String name;
private int age;
// 方法(行为)
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
// 其他方法...
}
(2)创建对象:一旦你定义了类,你就可以创建该类的对象。这是通过使用new关键字并调用类的构造函数来完成的。
MyObject myObject = new MyObject(); // 创建一个新的MyObject对象实例
(3)初始化对象:在创建对象后,你可能需要初始化其属性。这通常通过调用对象的setter方法来设置其属性值来完成.
myObject.setName("Alice"); // 设置对象的name属性值
myObject.setAge(25); // 设置对象的age属性值
(4)使用对象:一旦对象被创建并初始化,你就可以使用它的方法来执行操作或获取其属性值。
String objectName = myObject.getName(); // 获取对象的name属性值
二.构造方法
构造方法是用于初始化新创建的对象的方法。它具有与类名相同的名称,并且没有返回类型(包括void)。
public class Person {
private String name;
private int age;
// 默认构造方法
public Person() {
this.name = "Unknown";
this.age = 0;
}
// 带参数的构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 其他方法,如getter和setter等
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
注意:一个类可以有多个构造方法,只要它们的签名(参数列表)不同。这在Java中被称为构造方法的重载(Overloading)。通过使用重载的构造方法,你可以为类的对象提供多种不同的初始化方式。
三.this关键字
3.1引用当前对象
this关键字用于引用当前对象实例。当你在一个对象的成员方法内部需要引用这个对象本身时,你可以使用this。
public class MyClass {
private int value;
public void setValue(int value) {
this.value = value; // 使用this来引用当前对象的value字段
}
}
3.2构造器中的使用
在构造器中,你可以使用this来引用当前构造器中的参数,以区分局部变量和类的成员变量。
public class MyClass {
private int value;
public MyClass(int value) {
this.value = value; // 使用this来区分构造器的参数和类的成员变量
}
}
3.3在方法中明确当前对象
有时,在方法内部你可能需要明确表示你正在操作的是当前对象,而不是其他对象。这在你处理类似集合或数组等可能引起混淆的场景时特别有用。
3.4与继承的关系
当在一个子类的方法中使用this时,它通常指的是子类对象本身,而不是父类对象。但是,在某些情况下,你可能需要明确地使用super来引用父类。
注意事项:虽然this在某些情况下非常有用,但过度使用它可能会使代码难以阅读和理解。因此,建议只在真正需要明确当前对象时使用它。在大多数情况下,如果代码清晰明了,那么不使用this也是可以的。
四.static关键字
4.1静态变量
静态变量也称为类变量,因为它们属于类本身,而不是类的任何特定实例。所有实例共享相同的静态变量。静态变量在类加载时初始化一次,之后所有实例都可以访问这个变量。
public class MyClass {
public static int staticVar = 0; // 静态变量
}
4.2静态方法(Static Methods)
静态方法也属于类本身,而不是任何特定实例。因此,你可以通过类名直接调用静态方法,而无需创建类的实例。
public class MyClass {
public static void staticMethod() { // 静态方法
// ... 方法体 ...
}
}
五.包
5.1包的概念
包是一种将相关的类组织在一起的方式,以便更好地管理和重用代码。
5.2Java包的主要作用包括
1.代码组织:通过将相关的类放在同一个包中,可以使代码结构更加清晰。
2.防止命名冲突:不同的包可以有相同的类名,只要它们在不同的包中。
3.访问控制:Java的访问修饰符(如public、protected、默认(包内)访问和private)与包的概念相结合,可以控制类的访问级别。
4封装:包可以封装一组相关的类和方法,形成一个独立的单元。
5.3包的定义
package com.example.myapp;
public class MyClass {
// 类定义
}
六.面向对象的四大基本特征
6.1封装
封装是将数据(属性)和对数据的操作(方法)绑定起来,隐藏对象的内部状态,只对外提供公共访问方式。这有助于保护数据的安全性和完整性。
1.封装数据:在Java中,我们可以通过将数据(属性)定义为私有(private)来实现封装。这意味着其他类不能直接访问或修改这些数据。相反,我们提供公共(public)方法(通常称为getter和setter方法)来允许其他类以受控的方式访问和修改这些数据。
2.隐藏实现细节:封装不仅隐藏了数据的实际细节,还隐藏了对象如何工作的细节。这有助于我们保护代码的内部工作机制,只暴露必要的接口给外部使用。
3.提高代码安全性:通过封装,我们可以限制对对象数据的直接访问,从而减少错误的可能性。只有通过我们提供的公共方法,才能以正确的方式访问和修改数据。
4.代码重用和扩展性:封装使得我们可以创建可重用的代码块(即类),这些类可以单独编译和测试。此外,由于封装了数据和操作数据的方法,我们可以更容易地扩展或修改类的功能,而不会影响其他使用该类的代码。
5.类设计:在Java中,类是封装的主要单位。一个类可以包含多个方法和属性,这些方法和属性一起定义了类的行为和状态。通过将相关的属性和方法组合在一起,我们可以创建一个有意义的类,这个类可以代表现实世界中的一个实体或概念。
public class Person {
// 私有属性
private String name;
private int age;
// 公共构造方法,用于创建对象并初始化属性
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 公共getter和setter方法,用于访问和修改私有属性
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age > 0) { // 添加一些验证逻辑
this.age = age;
} else {
System.out.println("Age must be positive.");
}
}
}
Person类封装了姓名和年龄这两个属性。只有通过提供的公共方法(getter和setter),外部代码才能访问或修改这些属性。
6.2继承
1.继承是面向对象编程的一个核心概念,允许一个类(子类)继承另一个类(父类)的属性和方法。子类可以扩展或修改父类的功能,而无需重新编写父类的代码
2.使用关键字:使用extends关键字来声明一个类继承另一个类。例如,class SubClass extends ParentClass表示SubClass继承了ParentClass。
3.继承的层次结构:Java支持多层继承,这意味着一个类可以继承另一个类,而这个类又可以继承另一个类,以此类推。这种层次结构有助于组织代码和实现代码重用。
4.访问修饰符:在Java中,访问修饰符(如public、protected、default(包级私有)和private)决定了其他类如何访问一个类的成员(属性和方法)。继承时,子类只能访问父类的公共和受保护成员。
5.方法的重写(Override):子类有时可能需要修改从父类继承的方法的行为。在这种情况下,子类可以使用与父类方法相同名称和参数列表的方法,并使用@Override注解来明确表示这是一个重写的方法。这样,当子类对象调用该方法时,将执行子类中的实现,而不是父类中的实现。
6.super关键字:在子类中,可以使用super关键字来引用父类的成员。例如,super.methodName()用于调用父类的某个方法,super.variableName用于访问父类的某个变量。
7.继承的优缺点:
优点:代码重用、扩展功能、组织代码结构。
缺点:可能导致代码复杂性和耦合性增加,需要谨慎设计类和继承层次结构以避免不必要的复杂性。
8.默认继承:如果一个类没有明确使用extends关键字继承另一个类,那么它仍然隐式地继承了Object类的所有方法和属性。Object是Java中所有类的超类。
6.3多态
1.多态是指同一个接口可以由多种不同的类来实现。在运行时,根据对象的实际类型来确定调用哪个实现。这增加了代码的灵活性和可扩展性。
2.多态主要基于继承和接口,以及方法的重写(Override)和重载(Overload)。下面是一些关于Java面向对象多态的关键点:
(1)继承:在Java中,一个类可以继承另一个类的属性和方法。这使得我们可以创建一个通用的类,然后通过继承来创建更具体的类。
(1)方法重写(Override):在子类中,可以重写父类中的方法。这意味着子类提供了一个与父类同名但实现不同的方法版本。当通过父类引用调用该方法时,实际上会执行子类中的版本。
(2)多态性:这是当同一个接口引用可以指向多个不同类型对象时的行为。通过使用继承和方法重写,我们可以在运行时确定实际调用的方法版本。
(3)虚拟方法调用:在Java中,通过使用关键字virtual(尽管Java不直接使用此关键字,但概念相似),可以在运行时根据对象的实际类型来确定调用哪个方法。这就是多态的核心。
(4)实例化与引用:当你创建一个对象的实例时,你实际上是在创建一个特定类型的对象。但是,你可以使用一个更通用的类型(如父类类型)来引用这个对象。这就是多态性的一个关键点:使用父类类型的引用指向子类对象。
(5)动态绑定:在运行时,Java会根据对象的实际类型来确定调用哪个方法。这就是动态绑定或晚期绑定。
3.多态的实现
class Animal {
void makeSound() {
System.out.println("The animal makes a sound");
}
}
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("The dog barks");
}
}
class Cat extends Animal {
@Override
void makeSound() {
System.out.println("The cat meows");
}
}
public class PolymorphismExample {
public static void main(String[] args) {
Animal animal1 = new Dog(); // 使用Animal类型引用Dog对象
Animal animal2 = new Cat(); // 使用Animal类型引用Cat对象
animal1.makeSound(); // 实际上调用的是Dog的makeSound方法,输出"The dog barks"
animal2.makeSound(); // 实际上调用的是Cat的makeSound方法,输出"The cat meows"
}
}
6.4抽象类
1.概念:包含抽象方法和非抽象方法的类。抽象类不能直接实例化,只能作为其他类的基类。
2.抽象类的定义与使用
public abstract class Animal {
// 字段
private String name;
// 构造方法
public Animal(String name) {
this.name = name;
}
// 非抽象方法
public void eat() {
System.out.println(name + " is eating.");
}
// 抽象方法,子类必须实现这个方法
public abstract void makeSound();
}
七.Object类
Object类是所有类的超类,也就是说,所有的Java类都继承自Object类。Object类位于java.lang包中,因此在使用时无需显式导入。
Object类中定义了一些常用的方法,这些方法可以在任何对象上使用。以下是Object类中的一些主要方法:
1.equals(Object obj):用于比较两个对象的内容是否相等。默认实现是比较对象的引用,通常需要子类重写以实现基于内容的比较。
2.hashCode():返回对象的哈希码值,常与equals()方法一起使用在哈希表等数据结构中。
3.toString():返回对象的字符串表示形式。默认实现返回类名和哈希码的无意义字符串,通常需要子类重写以提供更有意义的描述。
4.getClass():返回对象的运行时类。
5.clone():创建并返回对象的一个副本。默认实现可能并不适用于所有对象,通常需要子类重写以提供正确的克隆行为(注意,对于不可变对象或那些不应被克隆的对象,这个方法可能并不适用)。
6.finalize():当垃圾收集器准备回收对象时调用此方法。这是一个保护性机制,通常不建议子类重写它,因为它依赖于具体的垃圾收集实现和时机。
八.接口
Java接口是一种定义方法但不实现方法的特殊类型。接口可以被看作是一种契约,定义了类应该具备的行为。任何类都可以实现一个接口,并按照接口中定义的方法进行实现。
// 定义一个接口
public interface Animal {
void eat();
void sleep();
}
// 实现Animal接口的Dog类
public class Dog implements Animal {
@Override
public void eat() {
System.out.println("Dog eats food.");
}
@Override
public void sleep() {
System.out.println("Dog sleeps.");
}
}
九.final关键字
9.1定义
final是一个关键字,它用于修饰类、方法或变量。final的主要目的是确保其修饰的元素在程序中是不可变的。
9.2实现
public final class FinalExample { // final类
public static final String CONSTANT_VALUE = "这是一个常量值"; // final静态变量
private final int finalValue; // final实例变量,必须在声明时或构造器中初始化
public FinalExample(int value) { // 构造器,finalValue必须在构造器中初始化
this.finalValue = value;
}
public final void finalMethod() { // final方法,不能在子类中被重写
// ... 方法实现 ...
}
}
十.内部类概述
内部类(Inner Class)是定义在一个类内部的另一个类。内部类提供了更好的封装和数据隐藏,并且可以更方便地访问外部类的属性和方法
定义与分类:成员内部类:定义在类的内部,但不作为外部类的方法存在。它可以访问外部类的所有成员(包括私有成员)。
局部内部类:定义在方法内部的类。它只能访问外部类的局部变量(如果这些变量是final的)。
静态内部类:在内部类前加上static关键字,使其成为静态内部类。静态内部类不依赖于外部类的实例,可以直接通过类名调用。
匿名内部类:没有名字的局部内部类,常用于简化代码编写,特别是实现接口或继承类的场景。