Java基础之面向对象
一、面向对象
1.1、面向对象概念
- 面向对象编程(Object-Oriented Programming, OOP)
- 面向对象编程的本质就是:以类的方式组织代码,以对象的形式封装数据
- 抽象:编程思想!持续的学习,茅塞顿开!多实践,多测试大脑中的想法!实践出真知
- 三大特性:封装,继承,多态
- 从认识论角度考虑是先有对象后有类。对象,是具体的事物。类,是抽象的,是对对象的抽象
- 从代码运行角度考虑是先有类后有对象。类是对象的模板
1.2、面向对象的三大特征
-
封装(Encapsulation): 封装是将对象的状态和行为包装在一起,并对外部隐藏对象的内部实现细节。通过使用 private 访问修饰符来限制对类的直接访问,通过公共的 getter 和 setter 方法来控制对对象状态的访问和修改。
-
继承(Inheritance): 继承允许一个类(子类/派生类)继承另一个类(父类/基类)的属性和行为。子类可以使用父类的成员,并且可以通过添加新的成员或修改现有成员来扩展或修改其行为。
-
多态(Polymorphism): 多态允许一个对象在不同的上下文中表现出不同的行为。它有两种形式:编译时多态(方法重载)和运行时多态(方法重写)。在运行时多态中,同一类的对象可以根据其实际类型调用不同的方法,这提高了代码的灵活性和可扩展性。
二、类与对象
2.1、构造方法
每个类都有构造方法。如果没有显式地为类定义构造方法,Java 编译器将会为该类提供一个默认构造方法。
在创建一个对象的时候,至少要调用一个构造方法。构造方法的名称必须与类同名,一个类可以有多个构造方法。
下面是一个构造方法示例:
java
public class Car{
public Car(){
}
public Car(String name){
//构造器只有一个参数:name
}
}
2.2、创建对象
对象是根据类创建的。在Java中,使用关键字 new 来创建一个新的对象。创建对象需要以下三步:
- 声明:声明一个对象,包括对象名称和对象类型。
- 实例化:使用关键字 new 来创建一个对象。
- 初始化:使用 new 创建对象时,会调用构造方法初始化对象。
下面是一个创建对象的实例:
java
public class Car{
public Car(){
}
public Car(String name){
//构造器只有一个参数:name
System.out.println("车的名字:"+name);
}
//一个类是一个模板,它描述了对象的属性和行为
//当我们实例化一个类时,我们创建了一个具体的对象,该对象具有类中定义的属性和行为
public static void main(String[] args){
//创建一个Car对象
Car myCar =new Car("BMW");
}
}
2.3、实例化
实例化是面向对象的一个概念,在创建对象和使用对象中使用。以下是实例化的过程和用法
2.3.1、什么是实例化
在Java中,实例化是指创建一个类的对象(instance)。类是一种抽象的模板,而实例是这个模板具体化后的一个具体对象。简而言之,实例化就是根据类的定义创建类的对象的过程。
实例化是通过使用new
关键字后跟构造函数来完成的。构造函数是类中的特殊方法,用于初始化对象的属性。
java
public class Car {
// 数据成员
private String brand;
private int year;
// 构造函数
public Car(String brand, int year) {
this.brand = brand;
this.year = year;
}
public String getBrand(){
return brand;
}
public int getYear(){
return year;
}
// 方法
public void start() {
System.out.println("The car is starting.\nit's name:"+brand+" \nit's year:"+year);
}
public static void main(String[] args){
//创建一个Car对象
Car myCar = new Car("Toyota", 2022);
myCar.start();
}
}
2.3.2、实例化的过程
当我们使用new关键字实例化一个对象时,实际上发生了以下几个步骤:
- 内存分配:Java会在内存中为对象分配一块空间,用于存储对象的属性值。
- 初始化:Java会调用类的构造方法来对对象进行初始化。构造方法是一个特殊的方法,用于初始化对象的属性。
- 返回引用:Java会返回一个指向新创建对象的引用。我们可以使用该引用来操作对象,如访问其属性或调用其方法。
2.3.3、实例化的用途
实例化Java对象有多种用途,包括:
- 创建对象:通过实例化一个类,我们可以创建一个具体的对象,用于存储和操作数据。
- 调用方法:通过实例化一个类的对象,我们可以调用该类的方法来执行特定的操作。例如,在上面的示例中,我们通过调用Car类的getBrand和getYear方法来获取对象的属性值。
- 传递参数:通过实例化一个类的对象,并将该对象作为参数传递给其他方法,我们可以在方法中使用该对象来执行特定的操作。
三、面向对象三大特征
3.1、封装
3.1.1、封装概念理解
封装是一种面向对象编程的原则,它将对象的内部细节隐藏在对象外部不可见的层次。封装有助于保护对象的状态,防止外部直接访问或修改对象的内部数据,从而提高代码的可维护性和安全性。
在封装中,通过使用访问修饰符(如 private
、protected
、public
)来限制对类的成员的访问。通常,类的字段(成员变量)被声明为私有(private
),而提供公共的方法(getter和setter)来允许外部访问和修改这些字段。
3.1.2、封装目标
- 隐藏内部实现细节: 封装将对象的内部实现细节隐藏在类的内部,只暴露必要的接口。这使得对象在不暴露其内部工作原理的情况下,可以被其他代码使用。
- 提供公共接口: 通过提供公共的方法,可以控制对对象的访问和修改。这使得可以在这些方法中添加逻辑,例如验证和处理,以确保对对象的安全操作。
- 增加灵活性: 封装提供了一种更改对象内部实现的灵活性,而不会影响与对象交互的其他代码。只要对象的公共接口保持不变,对象的内部实现可以自由地修改。
3.1.3、封装实现
在这个例子中,
Person
类封装了name
和age
两个私有字段,通过公共的getter和setter方法提供对这些字段的访问和修改。构造方法用于在创建对象时初始化这些字段的值。在setter方法中,可以添加逻辑进行验证,例如确保年龄不为负数。通过封装,Person
类隐藏了其内部实现细节,外部代码只能通过公共接口来与对象交互。
java
public class Person {
// 私有字段
private String name;
private int age;
// 构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 公共的getter方法用于获取私有字段的值
public String getName() {
return name;
}
public int getAge() {
return age;
}
// 公共的setter方法用于修改私有字段的值
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
// 在setter方法中可以添加逻辑进行验证
if (age > 0) {
this.age = age;
} else {
System.out.println("年龄不能为负数");
}
}
public static void main(String[] args) {
// 创建一个Person对象
Person person = new Person("John", 30);
// 通过getter方法获取私有字段的值
System.out.println("Name: " + person.getName());
System.out.println("Age: " + person.getAge());
// 通过setter方法修改私有字段的值
person.setName("Jane");
person.setAge(25);
// 再次通过getter方法获取修改后的值
System.out.println("Modified Name: " + person.getName());
System.out.println("Modified Age: " + person.getAge());
}
}
3.2、继承
3.2.1、继承概念理解
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
继承的特性:
- 子类拥有父类非 private 的属性、方法。
- 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
- 子类可以用自己的方式实现父类的方法。
- Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
- 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
3.2.2、继承的实现
继承可以使用 extends 和 implements 这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承 Object(这个类在 java.lang 包中,所以不需要 import)祖先类。
-
extends关键字
类的继承是单一继承、一个子类只能有一个父类,因此extends只能继承一个类
javapublic class Animal { private String name; private int id; public Animal(String myName, int myid) { //初始化属性值 } public void eat() { //吃东西方法的具体实现 } public void sleep() { //睡觉方法的具体实现 } } public class Dog extends Animal{ }
-
implements关键字
使用implements关键字可以使Java具有多继承的特性,只适用于类接口的情况。可以同时继承多个接口。
javapublic interface A { public void eat(); public void sleep(); } public interface B { public void show(); } public class C implements A,B { }
3.2.3、super和this关键字
-
super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
-
this关键字:指向自己的引用。
java
class Animal {
void eat() {
System.out.println("animal : eat");
}
}
class Dog extends Animal {
void eat() {
System.out.println("dog : eat");
}
void eatTest() {
this.eat(); // this 调用自己的方法
super.eat(); // super 调用父类方法
}
}
public class Test {
public static void main(String[] args) {
Animal a = new Animal();
a.eat();
Dog d = new Dog();
d.eatTest();
}
}
3.3、多态
多态:就是对象的多种表现形式。
即统一行为的不同表现形式(比如:发出叫声,不同的物种发出的声音不同)
代码示例:
java
// 动物类
class Animal {
void makeSound() {
System.out.println("发出通用动物声音");
}
}
// 狗类
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("汪汪汪!");
}
}
// 猫类
class Cat extends Animal {
@Override
void makeSound() {
System.out.println("喵喵喵!");
}
}
// 鹦鹉类
class Parrot extends Animal {
@Override
void makeSound() {
System.out.println("咕咕咕!");
}
}
// 动物园
public class Zoo {
public static void main(String[] args) {
// 使用多态,同样的方法调用会表现出不同的行为
Animal dog = new Dog();
Animal cat = new Cat();
Animal parrot = new Parrot();
dog.makeSound(); // 输出: 汪汪汪!
cat.makeSound(); // 输出: 喵喵喵!
parrot.makeSound(); // 输出: 咕咕咕!
}
}
3.3.1、多态的实现方式
- 方法一:重写。【参考:Java重写(Override)与重载(Overload)】
- 方法二:接口
- 方法三:抽象类和抽象方法
四、抽象类
4.1、抽象类概念理解:
在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
代码示例:
- 编写一个抽象类:
java
abstract class Shape {
abstract void draw();
void commonMethod() {
System.out.println("Common method in Shape class");
}
}
- 创建子类:
java
class Circle extends Shape {
@Override
void draw() {
System.out.println("Drawing a circle");
}
}
class Rectangle extends Shape {
@Override
void draw() {
System.out.println("Drawing a rectangle");
}
}
4.2、抽象类总结:
- 抽象类不能被实例化,如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象。
- 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
- 抽象类中的抽象方法只是声明,不包含具体方法体,就是不给出方法的具体实现也就是方法的具体功能。
- 构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。
- 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。
五、接口
5.1、接口概念理解:
它允许定义一组方法的声明,但没有提供这些方法的具体实现。接口是一种约定,指定了实现它的类应该具有哪些行为。
5.2、接口和类的区别:
- 接口不能用于实例化对象。
- 接口没有构造方法。
- 接口中所有的方法必须是抽象方法,Java 8 之后 接口中可以使用 default 关键字修饰的非抽象方法。
- 接口不能包含成员变量,除了 static 和 final 变量。
- 接口不是被类继承了,而是要被类实现。
- 接口支持多继承。
5.3、接口的特点
- 接口使用
interface
关键字声明。 - 接口中可以包含抽象方法和常量(
public static final
)。 - 接口中的方法默认是公有的(
public
)。 - 类通过
implements
关键字实现接口。且类实现接口时必须实现接口中的所有抽象方法。
5.4、接口声明
接口的声明:
java
[可见度] interface 接口名称 [extends 其他的接口名] {
// 声明变量
// 抽象方法
}
示例:
java
//接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字。
//接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键字。
interface MyInterface {
// 抽象方法的声明
void myAbstractMethod();
public void eat();
// 接口中的常量
int MAX_VALUE = 100;
}
5.5、接口实现
一个类通过使用 implements
关键字来实现一个或多个接口。实现接口的类必须提供接口中定义的所有抽象方法的具体实现。
代码示例
java
interface MyInterface {
void myMethod();
}
class MyClass implements MyInterface {
@Override
public void myMethod() {
// 具体实现
}
}
5.5.1、实现多个接口
java
interface Interface1 {
void method1();
}
interface Interface2 {
void method2();
}
class MyClass implements Interface1, Interface2 {
@Override
public void method1() {
// 实现 Interface1 中的方法
}
@Override
public void method2() {
// 实现 Interface2 中的方法
}
}
5.5.2、静态方法/常量的实现
接口中的静态方法可以直接在接口中调用/接口中的常量是隐式地被 public static final
修饰的,实现类不需要提供对静态方法/常量的具体实现。
java
interface MyInterface {
static void myStaticMethod() {
// 静态方法实现
}
int MAX_VALUE = 100; // 常量
}
class MyClass implements MyInterface {
// 不需要提供对静态方法的具体实现
}
5.6、实现类的注意事项
- 实现类必须提供接口中所有抽象方法的具体实现,否则该类必须声明为抽象类。
- 如果一个类同时继承类(extends)和实现接口(implements),
extends
关键字应该在implements
关键字之前。
java
class MyConcreteClass extends MyParentClass implements MyInterface {
// 提供对接口和父类的具体实现
}