面向对象基本概念
面向对象相关的一些常见术语的解释
-
面向对象(
Object-Oriented,OO
):一种程序设计方法,将真实世界中的事物抽象成对象,并通过封装、继承和多态等特性来描述和操作对象的状态和行为。 -
面向对象编程(
Object-Oriented Programming,OOP
):基于面向对象思想的一种编程范式,通过创建和操作对象来实现程序的模块化、重用和可维护性。 -
面向对象分析(
Object-Oriented Analysis,OOA
):软件工程中的一个阶段,通过分析问题域中的概念、属性和关系等,识别和定义出系统中的对象及其交互,以获取对问题域的深入理解。 -
面向对象设计(
Object-Oriented Design,OOD
):软件工程中的一个阶段,基于面向对象分析的结果,将系统功能划分为一组对象,并定义它们的属性、行为和关系,以实现系统的模块化和可扩展性。 -
面向对象语言(
Object-Oriented Language
):支持面向对象编程的编程语言,如Java、C++、Python等,这些语言提供了类、对象、继承、多态等面向对象特性的语法和语义。
面向对象(Object-Oriented)是一种软件开发的编程范式,它将现实世界中的事物抽象为对象,并通过对象之间的相互作用来实现程序的设计和开发。面向对象编程具有以下基本概念:
-
类(Class):类是面向对象的基本概念,表示一类具有相同属性和行为的对象的抽象模板。类定义了对象的属性(成员变量)和行为(方法)。
-
对象(Object):对象是类的一个实例,可以具体地表示现实世界中的一个事物。每个对象都有自己的状态(属性值)和行为(方法)。
-
封装(Encapsulation):封装是将类的数据(属性)和操作(方法)包装在一起,以隐藏内部实现细节,仅对外提供公共接口。通过封装,可以保护数据的安全性和完整性。
-
继承(Inheritance):继承是指在已有类的基础上创建新类,新类继承了已有类的属性和方法。通过继承,子类可以复用父类的代码,并可以添加、修改或覆盖父类的方法。
-
多态(Polymorphism):多态是指同一类型的对象,在不同的情况下表现出不同的行为。多态通过方法的重写(Override)和方法的重载(Overload)来实现。
-
抽象(Abstraction):抽象是指将对象的共同特征提取出来,形成抽象类或接口。抽象类定义了一组抽象方法和非抽象方法,而接口只包含抽象方法。通过抽象,可以实现代码的模块化和复用。
类与对象
类(Class)和对象(Object)是面向对象编程的基本概念,它们之间有着紧密的关系。
-
类是对一类事物的抽象描述,它定义了对象的属性和行为。通过类可以创建多个具体的对象实例。类是对象的模板,包含了共同的属性和行为,但不具体表示任何特定的对象。
-
对象是类的一个实例,代表了现实世界中的一个具体事物。对象具有自己的状态(属性值)和行为(方法),可以通过调用对象的方法来操作其状态。每个对象都是独立存在的,它们之间相互独立,拥有各自的属性值和执行过程。
-
类和对象之间的关系可以理解为类是对象的蓝图或模板,而对象是根据类的定义创建出来的具体实体。类可以看作是对象的抽象,而对象是类的具体化。
类和对象的定义格式
在Java中可以使用以下的语句定义一个类:
class 类名称{ 属性名称; 返回值类型 方法名称(){} }
对象的定义: 一个类要想真正的进行操作,则必须依靠对象,对象的定义格式如下:
类名称 对象名称 = new 类名称() ;
按照以上的格式就可以产生对象了。 如果要想访问类中的属性或方法(方法的定义),则可以依靠以下的语法形式:
-
访问类中的属性: 对象.属性 ;
-
调用类中的方法: 对象.方法()
对象内存分析
-
new关键字:表示向内存申请空间,也表示实例化一个对象,创建一个对象。
-
一个对象在内存中的大小,由该对象的所有属性所占的内存大小的总和。引用类型变量在32位系统上占4个 字节,在64位系统上占8个字节。加上而外的对象隐性数据所占的大小。
-
相同的类型才可以赋值
-
不同的引用,指向同一个对象,任何一个引用改变对象的值,其它引用都会反映出来。
-
编程时要注意的问题,在确定不使用对象时,要尽早释放对象:引用=null
-
当一个堆中的对象没有被任何引用变量所指向时,该对象会被
JVM
的GC
程序认为是垃圾对象,从而被回 收。
封装
封装的基本概念
封装性
-
封装性是面向对象思想的三大特征之一。
-
封装就是隐藏实现细节,仅对外提供访问接口。
-
封装有: 属性的封装、方法的封装、类的封装、组件的封装、模块化封装、系统级封装…
封装的好处
-
模块化
-
信息隐藏
-
代码重用
-
插件化易于调试
-
具有安全性
封装缺点
-
会影响执行效率
封装之前
class Person{ String name; int age; }
封装之后
class Person{ //属性是成员变量 private String name; private int age; //参数及方法内定义的变量是局部变量 public void setName(String name){ this.name = name; } public String getName(){ return name; } }
成员变量和局部变量
-
在类中的位置不同 成员变量:在类中定义 局部变量:在方法中定义或者方法的参数
-
在内存中的位置不同 成员变量:在堆内存(成员变量属于对象,对象进堆内存) 局部变量:在栈内存(局部变量属于方法,方法进栈内存)
-
生命周期不同 成员变量:随着对象的创建而存在,随着对象的销毁而消失 局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
-
初始化值不同 成员变量:有默认初始化值,引用类型默认为null 局部变量:没有默认初始化值,必须定义,赋值,然后才能使用
-
注意: 局部变量名称可以和成员变量名称一样,在方法中使用的时候,采用的是就近原则。
构造方法
什么是构造方法
-
构造方法就是类构造对象时调用的方法,用于对象的初始化工 作
-
构造方法是实例化一个类的对象时,也就是new 的时候,最先调用的方法。
构造方法的定义
-
构造方法是在类中定义的
-
构造方法的定义格式
-
方法名称与类名称相同,无返回值类型的声明。
-
-
对象的实例化语法:
-
Dog dog = new Dog(); //new Dog后面有个括号,带括号表示调用了方法,此时调用的方法就是构造方法了
-
无参构造方法:
public Dog(){} 带一个参数的构造方法: public Dog(String name){ this.name = name; } }
带多个参数的构造方法
public Dog(String name,int age){ this.name = name; this.age = age; }
构造方法小结
-
构造方法名称与类名相同,没有返回值声明(包括 void)
-
构造方法用于初始化数据(属性)
-
每一个类中都会有一个默认的无参的构造方法
-
如果类中有显示的构造方法,那么默认构造方法将无效
-
如果有显示的构造方法,还想保留默认构造 方法,需要显示的写出来。
-
构造方法可以有多个,但参数不一样,称为构造方法的重载
-
在构造方法中调用另一个构造方法,使用this(...),该句代码必须在第一句。
-
构造方法之间的调用,必须要有出口。
-
给对象初始化数据可以使用构造方法或setter方法,通常情况下,两者都会保留。
-
一个好的编程习惯是要保留默认的构造方法。(为了方便一些框架代码使用反射来创建对象)
-
private Dog(){},构造方法私有化,当我们的需求是为了 保正该类只有一个对象时。
什么时候一个类只需要一个对象?
比如,工具类(没有属性的类,只有行为)并且该工具对象被频繁使用。 权衡只用一个对象与产生多个对象的内存使用,来确定该类是否要定义为只需要一个对象。
this关键字
在Java基础中,this关键字是一个最重要的概念。使用this关键字可以完成以下的操作:
-
调用类中的属性
-
调用类中的方法或构造方法
-
表示当前对象
在Java中,关键字 "this" 代表当前对象的引用。它可以用于以下几种情况:
-
引用当前对象的成员变量:在类的实例方法中,可以使用 "this" 关键字来引用当前对象的成员变量。这样可以区分成员变量和方法参数之间的命名冲突。
public class Person { private String name; public void setName(String name) { this.name = name; // 使用 "this" 引用当前对象的成员变量 } }
-
调用当前对象的其他方法:在类的实例方法中,可以使用 "this" 关键字来调用当前对象的其他方法。这样可以在方法内部方便地访问对象的其他行为。
public class Calculator { private int result; public void add(int num) { result += num; } public void printResult() { System.out.println("Result: " + this.getResult()); // 使用 "this" 调用当前对象的方法 } public int getResult() { return result; } }
-
在构造方法中引用其他构造方法:当一个类中存在多个构造方法时,可以使用 "this" 关键字在一个构造方法中调用其他构造方法。这样可以避免代码的重复。
public class Rectangle { private int width; private int height; public Rectangle() { this(0, 0); // 调用带参数的构造方法 } public Rectangle(int width, int height) { this.width = width; this.height = height; } }
总之,"this" 关键字在Java中表示当前对象的引用。它可以用于引用当前对象的成员变量、调用当前对象的其他方法以及在构造方法中调用其他构造方法。使用 "this" 可以解决命名冲突、方便访问对象的其他行为,并提高代码的可读性和重用性。
static关键字
static关键字的作用:
-
使用static关键字修饰一个属性 声明为static的变量实质上就是全局变量
-
使用static关键字修饰一个方法 通常,在一个类中定义一个方法为static,那就是说,无需本类的对象即可调用此方法
-
使用static关键字修饰一个类(内部类)
"static" 关键字的主要用法
当我们在Java中使用 "static" 关键字修饰某个成员(字段或方法)时,它的含义是这个成员不再属于实例对象,而是属于类本身。这意味着无需创建实例对象,就可以直接访问和使用这个成员。
举例来说,假设我们有一个叫做 "Person" 的类,我们希望记录创建过多少个实例对象。我们可以使用一个静态变量来实现这个功能:
public class Person { private static int count; // 静态变量,用于记录创建的实例对象数量 private String name; public Person(String name) { this.name = name; count++; // 每次创建实例对象时,通过静态变量自增来记录数量 } public void sayHello() { System.out.println("Hello, my name is " + name); } public static int getCount() { return count; // 静态方法可以直接访问静态变量 } }
现在我们可以创建多个 "Person" 实例对象,并查看创建的对象数量:
Person p1 = new Person("Alice"); Person p2 = new Person("Bob"); System.out.println(Person.getCount()); // 输出:2
在这个例子中,静态变量 "count" 被所有的 "Person" 实例对象所共享。每次创建实例对象时,静态变量都会自增,记录了创建的实例对象数量。我们可以通过静态方法 "getCount()
" 直接访问静态变量,而无需创建实例对象。
总的来说,使用 "static" 关键字将成员修饰为类级别的,使得它们不再属于实例对象,而是属于类本身。这样可以直接通过类名访问和使用这些成员,而不需要先创建实例对象。
main方法分析
public static void main(String[] args){ //代码块 }
-
public:公有的,最大的访问权限
-
static:静态的,无需创建对象
-
void::表示没有返回值,无需向
JVM
返回结果 -
main:方法名,固定的方法名
-
String[]
args
:表示参数为字符串数组,可以在调用方法时传入参数
继承
继承的基本概念
继承是从已有的类创建新类的过程
1、继承是面向对象三大特征之一 2、被继承的类称为父类(超类),继承父类的类称为子类(派生类) 3、继承是指一个对象直接使用另一对象的属性和方法。 4、通过继承可以实现代码重用
语法
语法:[访问权限] class 子类名 extends 父类名{ 类体定义; }
示例
public class Dog{ private String name; private String sex; public void eat(){ System.out.println(“吃饭”); } } public class HomeDog extends Dog{ //类的定义 } public class HuskyDog extends Dog{ //类的定义 }
-
protected(受保护的访问权限修饰符,用于修饰属性和方法,使用protected修饰的属性和方法可以被子类继承)
继承的限制
继承的限制约定:
-
Java只能实现单继承,也就是一个类只能有一个父类
-
允许多层继承,即:一个子类可以有一个父类,一个父类还可以有其他的父类。
-
继承只能继承非私有的属性和方法。
-
构造方法不能被继承
继承的好处:
-
提高代码的复用性
-
提高代码的维护性
-
让类与类之间产生关系,是多态的前提
继承的缺点:
-
增强了类与类之间的耦合性(开发原则:高内聚,低耦合)
继承小结
-
继承是发生在多个类之间
-
继承使用关键字extends
-
JAVA只能单继承,允许多层继承
-
被继承的类叫父类(超类),继承父类的类叫子类(派生类)
-
在父类中的非私有属性和方法可以被子类继承
-
protected(受保护的访问权限修饰符),修饰的属性或方法可以被子类继承
-
构造方法不能被继承
-
创建对象会调用构造方法,调用构造方法不一定就是创建对象
-
实例化子类对象,会先调用父类的构造方法,如果父类中没有默认的构造方法,那么子类必须显示的通过 super(...)来调用父类的带参构造方法,super也只能在子类构造方法中的第一句
子类的实例化过程
在子类进行实例化操作的时候,首先会先让其父类进行初始化操作。之后子类再自己进行实例化操作。 子类的实例化过程:
-
子类实例化时会先调用父类的构造方法
-
如果父类中没有默认的构造方法,在子类的构造方法中必须显示的调用父类的构造方法
结论:
-
构造方法只是用于初始化类中的字段以及执行一些初始化代码
-
调用构造方法并不代表会生成对象
方法的重写
方法重写(overriding method)
在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想做一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。在子类和父类中,重写方法后,在调用时,以创建的对象类型为准,会调用谁的方法。
关于方法重写的一些特性:
-
发生在子父类中,方法重写的两个方法返回值、方法名、参数列表必须完全一致(子类重写父类的方法)
-
子类抛出的异常不能超过父类相应方法抛出的异常(子类异常不能大于父类异常)
-
子类方法的访问级别不能低于父类相应方法的访问级别(子类访问级别不能低于父类访问级别)
-
父类中的方法若使用private、static、final任意修饰符修饰,那么,不能被子类重写。
为什么要重写方法?或者方法重写的目的是什么?
若子类从父类中继承过来的方法,不能满足子类特有的需求时,子类就需要重写父类中相应的方法,方法的重写 也是程序扩展的体现。
super关键字
super可以完成以下的操作:
-
使用super调用父类中的属性,可以从父类实例处获得信息。
-
使用super调用父类中的方法,可以委托父类对象帮助完成某件事情。
-
使用super调用父类中的构造方法(super(实参)形式),必须在子类构造方法的第一条语句,调用父类中相应 的构造方法,若不显示的写出来,默认调用父类的无参构造方法,比如:super();
举例子
假设有一个父类Person
和一个子类Student
,子类Student
继承了父类Person
,我们来看一下在实际代码中如何使用super
关键字。
class Person { String name; public Person(String name) { this.name = name; } public void display() { System.out.println("Person: " + name); } } class Student extends Person { int grade; public Student(String name, int grade) { super(name); // 调用父类的构造函数 this.grade = grade; } @Override public void display() { super.display(); // 调用父类的display方法 System.out.println("Student Grade: " + grade); } } public class Main { public static void main(String[] args) { Student student = new Student("Alice", 10); student.display(); } }
在上面的示例中,子类Student
继承了父类Person
的实例变量name
和方法display
。使用super(name)
调用父类的构造函数来初始化父类的实例变量。在子类的display
方法中,使用super.display()
调用父类的display
方法,并在其基础上添加了其他功能。
运行上述代码,输出结果为:
Person: Alice Student Grade: 10
可以看到,通过使用super
关键字,我们能够在子类中访问父类的变量、方法或构造函数,并在其基础上进行修改和扩展。
final关键字
使用final关键字完成以下的操作:
-
使用final关键字声明一个常量 修饰属性或者修饰局部变量(最终变量),也称为常量。
-
使用final关键字声明一个方法 该方法为最终方法,且只能被子类继承,但是不能被子类重写。
-
使用final关键字声明一个类 该类就转变为最终类,没有子类的类,fianl修饰的类无法被继承。
-
在方法参数中使用final,在该方法内部不能修改参数的值
final应用:
//定义一个常量: public static final int NUM = 10; //定义一个final方法(不常用) //定义一个final类:通常在常量类中使用 //常量类:在该类中只有常量,通常是应用程序中公共的常量或标记 public final class Constant{ public static final String SERVER_ROOT_URL ="http://www.baidu.com"; public static final String CACHE_PATH ="data_cache"; //.... }
多态
抽象类
抽象类的基本概念
-
很多具有相同特征和行为的对象可以抽象为一个类;很多具有相同特征和行为的类可以抽象为一个抽象类。
-
使用abstract关键字声明的类为抽象类。
定义一个抽象类
在Java中,可以使用关键字 "abstract" 来定义一个抽象类。抽象类是一种不能被直接实例化的类,它通常用作其他具体子类的基类。
要定义一个抽象类,需要按照以下步骤进行:
-
使用关键字 "abstract" 在类声明前面进行修饰。
-
可以在抽象类中定义抽象方法,这些方法没有具体的实现。抽象方法使用关键字 "abstract" 进行修饰,并且不包含方法体。
-
抽象类中可以包含具体的方法,这些方法有具体的实现代码。
-
抽象类可以拥有字段和构造函数。
以下是一个简单的示例,展示如何定义一个抽象类:
abstract class Animal { private String name; public Animal(String name) { this.name = name; } public void sleep() { System.out.println(name + " is sleeping."); } public abstract void makeSound(); // 抽象方法,无具体实现 public abstract void move(); // 抽象方法,无具体实现 }
在上述示例中,我们定义了一个名为 "Animal" 的抽象类。它有一个私有字段 "name" 和一个构造函数来初始化这个字段。抽象类中还有一个具体的方法 "sleep",它输出动物正在睡觉。另外,还定义了两个抽象方法 "makeSound
" 和 "move",这些方法没有具体的实现。
请注意,由于抽象类不能直接实例化,因此我们无法创建 "Animal" 类的对象。我们可以通过继承抽象类并实现其中的抽象方法来创建具体的子类,从而实例化对象。
例如,我们可以创建一个名为 "Dog" 的子类来继承 "Animal" 抽象类,并实现抽象方法:
class Dog extends Animal { public Dog(String name) { super(name); } @Override public void makeSound() { System.out.println("Woof woof!"); } @Override public void move() { System.out.println("Running on four legs."); } }
在上述示例中,我们创建了一个名为 "Dog" 的子类,继承自 "Animal" 抽象类。我们必须实现抽象方法 "makeSound
" 和 "move",提供具体的实现逻辑。
通过定义抽象类,我们可以为一组相关的类定义共同的行为和结构,同时要求具体的子类实现抽象方法。这样可以提高代码的可维护性和灵活性。
抽象类的规则:
-
抽象类可以没有抽象方法,有抽象方法的类必须是抽象类
-
非抽象类继承抽象类必须实现所有抽象方法
-
抽象类可以继承抽象类,可以不实现父类抽象方法。
-
抽象类可以有方法实现和属性
-
抽象类不能被实例化
-
抽象类不能声明为final
-
抽象类可以有构造方法
接口
接口的概念
-
接口是一组行为的规范、定义,没有实现(
JDK1.8
默认方法) -
使用接口,可以让我们的程序更加利于变化
-
接口是面向对象编程体系中的思想精髓之一
-
面向对象设计法则:基于接口编程
接口的定义格式:
public interface 接口名称 { // 声明常量 // 声明方法(默认抽象方法) // 可选:声明默认方法 // 可选:声明静态方法 }
接口的使用规则:
-
定义一个接口,使用interface关键字
-
在一个接口中,只能定义常量、抽象方法,
JDK1.8
后可以定义默认的实现方法 -
接口可以继承多个接口:extends
xxx
,xxx
-
一个具体类实现接口使用implements关键字
-
一个类可以实现多个接口
-
抽象类实现接口可以不实现接口的方法
-
在接口中定义的方法没有声明 访问修饰符,默认为public
-
接口不能有构造方法
-
接口不能被实例化
举例子
public interface Flyable { int MAX_SPEED = 100; // 声明常量 void fly(); // 声明抽象方法 default void takeOff() { // 默认方法的具体实现 System.out.println("Taking off..."); } static void land() { // 静态方法的具体实现 System.out.println("Landing..."); } } class Bird implements Flyable { @Override public void fly() { System.out.println("Bird is flying."); } } class Airplane implements Flyable { @Override public void fly() { System.out.println("Airplane is flying."); } } public class Main { public static void main(String[] args) { Bird bird = new Bird(); bird.fly(); // 输出:Bird is flying. bird.takeOff(); // 输出:Taking off... Flyable.land(); // 输出:Landing... Airplane airplane = new Airplane(); airplane.fly(); // 输出:Airplane is flying. airplane.takeOff(); // 输出:Taking off... Flyable.land(); // 输出:Landing... } }
对于默认方法和静态方法,在接口中可以提供具体的默认实现或静态实现,实现类可以选择是否重写这些方法。
默认方法使用关键字 default
进行修饰,它们在接口中有一个默认的实现代码。实现类可以直接继承默认方法的实现,也可以选择重写。
静态方法使用关键字 static
进行修饰,它们在接口中有一个具体的静态实现。静态方法是基于接口本身而不是实现类的,可以直接通过接口名调用,无需实例化对象。
在上述代码中,takeOff()
是一个默认方法,它提供了一个默认的具体实现代码,输出"Taking off..."。如果实现类没有重写该方法,将使用默认实现。
land()
是一个静态方法,它也提供了一个具体的静态实现代码,输出"Landing..."。静态方法可以直接通过接口名调用,例如 Flyable.land()
。
因此,实现类可以选择是否重写这两个方法。如果不需要自定义实现,可以直接使用接口中提供的默认实现或静态实现。
多态的基本概念
在Java中,多态性(Polymorphism)是指同一类型的对象,通过引用不同的类而表现出不同的行为。简而言之,多态性允许我们使用父类的引用来引用子类的对象,从而实现对不同子类的统一处理。
多态性有两种形式:编译时多态和运行时多态。
-
编译时多态(静态多态):在编译时,Java编译器会根据引用变量的类型来确定可以调用的方法。这意味着编译时多态仅限于编译器可见的类型,即基于引用变量的类型调用相应的方法。这种多态只能适用于非静态方法,并且是通过继承和方法重写来实现的。
-
运行时多态(动态多态):在运行时,Java的虚拟机根据对象的实际类型来确定要调用的方法。这意味着运行时多态能够动态地根据对象的类型调用相应的方法。这种多态性是通过继承、方法重写和父类引用指向子类对象来实现的。
多态性的好处在于它可以让代码更加灵活和可扩展。通过多态性,我们可以编写通用的代码,而不需要为每个子类编写特定的代码。
以下是一个示例,展示了多态性的用法:
class Animal { public void makeSound() { System.out.println("Animal is making a sound."); } } class Dog extends Animal { @Override public void makeSound() { System.out.println("Dog is barking."); } } class Cat extends Animal { @Override public void makeSound() { System.out.println("Cat is meowing."); } } public class Main { public static void main(String[] args) { Animal animal1 = new Dog(); // 使用父类引用指向子类对象 Animal animal2 = new Cat(); // 使用父类引用指向子类对象 animal1.makeSound(); // 输出:Dog is barking. animal2.makeSound(); // 输出:Cat is meowing. } }
在上述示例中,我们有一个基类 Animal
和两个派生类 Dog
和 Cat
。这三个类都有一个名为 makeSound()
的方法,但是每个子类都重写了该方法以实现自己的行为。
在主程序中,我们创建了一个 Animal
类型的引用变量 animal1
和 animal2
,并将它们分别指向一个 Dog
对象和一个 Cat
对象。然后,我们通过这两个引用变量调用 makeSound()
方法。由于运行时多态性的存在,根据对象的实际类型,正确的方法会被动态地调用,输出相应的结果。这就是多态性的运行时表现。
总结起来,多态性是Java面向对象编程的一个重要概念,它通过父类引用指向子类对象,实现对不同子类对象的统一处理。多态性可以提高代码的灵活性、可扩展性和可维护性。
多态性小结:
-
方法的重载与重写就是方法的多态性表现
-
多个子类就是父类中的多种形态
-
父类引用可以指向子类对象,自动转换
-
子类对象指向父类引用需要强制转换(注意:类型不对会报异常)
-
在实际开发中尽量使用父类引用(更利于扩展)
instanceof
关键字
在Java中,instanceof
是一个关键字用于检查一个对象是否属于某个特定类的实例,或者是其子类的实例。它可以用于在运行时判断一个对象的真实类型,以便进行相应的操作。
instanceof
的语法格式如下:
object instanceof class
其中,object
是待检查的对象,class
是要检查的类名或接口名。
当 object
是 class
类的实例(或其子类的实例)时,instanceof
返回 true
;否则,返回 false
。
以下是一个示例代码,演示了 instanceof
的用法:
class Animal { // 父类的方法 } class Dog extends Animal { // 子类的方法 } class Cat extends Animal { // 子类的方法 } public class Main { public static void main(String[] args) { Animal animal1 = new Dog(); Animal animal2 = new Cat(); if (animal1 instanceof Dog) { Dog dog = (Dog) animal1; dog.bark(); // 调用 Dog 类的方法 } if (animal2 instanceof Cat) { Cat cat = (Cat) animal2; cat.meow(); // 调用 Cat 类的方法 } } }
在上述示例中,我们有一个基类 Animal
和两个派生类 Dog
和 Cat
,每个类都有自己的方法。
在主程序中,我们创建了一个 Animal
类型的引用变量 animal1
和 animal2
,并将它们分别指向一个 Dog
对象和一个 Cat
对象。
我们使用 instanceof
关键字来检查 animal1
和 animal2
的类型。如果 animal1
是 Dog
类的实例,则将其转型为 Dog
类,并调用 bark()
方法。如果 animal2
是 Cat
类的实例,则将其转型为 Cat
类,并调用 meow()
方法。
通过使用 instanceof
关键字,我们可以在运行时检查对象的类型,以便根据实际情况执行相应的操作。这在处理继承关系中的多态性时非常有用。需要注意的是,在进行类型转换时,我们通常应该先使用 instanceof
进行检查,以确保对象的类型是正确的,避免出现类型转换异常(ClassCastException)。
总结来说,instanceof
关键字是Java中用于检查对象类型的机制,用于判断一个对象是否是某个类的实例或其子类的实例。它可以帮助我们进行类型检查,以便在运行时执行适当的操作。
总结
Java是一种面向对象的编程语言,它支持面向对象编程的核心概念和特性。下面是对Java面向对象的总结:
-
类和对象:Java通过类(Class)来定义对象(Object)。类是一个模板,描述了对象的属性(成员变量)和行为(方法)。对象是类的一个实例,具有自己的状态和行为。
-
封装(Encapsulation):封装是将数据和代码包装在一个单个实体中的机制。在Java中,我们可以使用访问修饰符(如private、public、protected)来控制成员变量和方法的访问权限,以实现数据的隐藏和保护。
-
继承(Inheritance):继承是一种机制,允许一个类继承另一个类的属性和方法。子类(派生类)可以继承父类(基类)的特性,并且可以在此基础上添加自己的额外功能。继承可以提高代码的可重用性和可扩展性。
-
多态(Polymorphism):多态性是指同一个类型的对象,在不同情况下表现出不同的行为。通过继承和方法重写,子类可以覆盖父类的方法,从而实现多态性。多态性使得代码更加灵活,能够处理不同类型的对象。
-
抽象(Abstraction):抽象是隐藏对象的复杂性,只展示必要的信息和功能。在Java中,我们可以使用抽象类(Abstract Class)和接口(Interface)来定义抽象类型,这些类型不能被实例化,但可以被继承或实现。
-
接口(Interface):接口是一种约定,规定了类需要实现的方法。接口定义了一组方法的声明,而没有提供方法的实现。类可以实现一个或多个接口,以满足接口所定义的契约。
-
构造函数(Constructor):构造函数是一种特殊类型的方法,用于创建和初始化对象时调用。它具有与类相同的名称,并且没有返回类型。构造函数在使用
new
关键字创建对象时被自动调用。 -
成员变量和方法:类包含成员变量和方法。成员变量是类的属性,用于存储对象的状态。方法是类的行为,用于操作和处理数据。
-
包(Package):包是一种组织类和接口的机制,用于避免命名冲突。通过将类和接口组织在包中,可以更好地管理和维护代码。
-
异常处理(Exception Handling):Java提供了异常处理机制,用于处理程序运行过程中可能出现的错误。通过捕获和处理异常,可以使程序更加健壮和稳定。
通过使用这些面向对象的概念和特性,Java程序可以更加模块化、可读性和可维护性。面向对象编程使得代码更加易于理解和重用,并促进了软件开发过程中的抽象和分离。