Java 面向对象
面向对象编程(Object-Orientend Programma,OOP)是一种编程范式,她将程序中数据(对象)和操作数据的方法(函数)组织为相互关联的对象,以模拟现实世界的概念和关系。在面向对象编程中,程序被视为一组对象的集合,这些对象通过相互协作来完成任务。
Java是一种典型的面向对象编程语言,以下是面向对象编程的核心概念:
- **对象(Object):**对象是现实世界中的实体或数据,具有状态(属性)和方法(行为)。在编程中,对象是类的实例,可以通过类来创建。
- **类(Class):**类是对象的模板或蓝图,用于定义对象的属性(成员变量)和方法(成员方法)。类描述了对象的结构和行为。
- **封装(Encapsulation):**封装是面向对象编程的核心原则之一,他将数据和方法组合在一个单元中,并将其限制在类的内部。通过封装,对象的内部细节对外部代码隐藏,只暴露必要的接口。
- **继承(Inheritance):**继承是一种机制,它允许创建一个新的类(子类或派生类),该类可以继承现有类(父类或基类)的属性和方法。继承提供了代码重用和扩展的能力。
- **多态(Polymorphism):**多态允许不同的对象相同的方法做出不同的响应。这是通过方法的重写(覆盖)和方法的重载(多态性)来实现的。多态增加了代码的灵活性和可扩展性。
- **抽象(Abstract):**抽象是将复杂的现实世界问题简化为程序的关键概念和功能的过程。抽象可以通过抽象类和接口来实现,他们定义了一组抽象方法,具体实现又子类提供。
- **消息传递(Message Passing):**在面向对象编程中,对象之间通过消息传递来进行通信。一个对象可以向另一个对象发送消息,触发特定的操作或方法调用。
- **类和对象关系:**在面向对象编程中,类和对象之间有以下关系:
- 实例化:创建对象时,根据类的定义来构造对象。
- 继承:子类继承父类的属性和方法,可以重用和扩展
- 关联:类可以与其他类关联,形成对象之间的关系,如聚合和组合。
类和对象的创建
创建类:
-
**定义类名和访问修饰符:**首先,您需要定义类的名称并选择适当的访问修饰符,如
public
、private
、protected
或默认(没有修饰符)public class MyClass { // 类的成员变量和方法将在这里定义 }
-
**定义成员变量:**在类中定义成员变量,也称为属性或字段,用于表示类的状态。
public class MyClass { int myVariable; // 一个整数类型的成员变量 }
-
**定义方法:**在类中定义成员方法,用于表示类的行为或功能。
public class MyClass { int myVariable; void myMethod() { // 方法的具体实现将在这里定义 } }
-
**创建构造函数(可选):**如果需要在创建对象时进行初始化操作,可以定义一个构造函数。构造函数的名称与类名相同
public class MyClass { int myVariable; // 构造函数 public Myclass() { // 构造函数的具体实现将在这里定义 } }
创建对象:
一旦定义了类,就可以使用new
关键字来创建类的对象。对象是类的实例,它可以访问类中成员变量和方法。
Myclass myobject = new Myclass(); //创建 Myclass 类的对象
通过上述步骤,你创建了一个名为myObject
的MyClass
类的对象。现在,您可以该对象来访问类中的成员变量和方法:
myObject.myVariable = 42; // 设置对象的成员变量值
myObject.myMethod(); // 调用对象的方法
请注意以下重要概念:
- 类是一个模板,对象是该模板的实例。
- 每个对象都有自己的状态(成员变量)和行为(方法)。
- 类的构造函数用于初始化对象的转态。
- 对象是通过类是构造函数来创建的。
构造器详解:
Java中,构造器(Constructor)是一种特殊的方法,用于创建和初始化对象。构造器在对象创建时自动调用,确保对象在被使用之前处于一个有效的状态。
-
**构造器的命名:**构造器的名称必须与类的名称完全相同,包括大小写。它没有返回类型,甚至不是
void
-
**默认构造器:**如果您未显示定义任何构造器,Java会自动为您生成一个无参数的默认构造器。默认构造器没有参数,但它仍然存在于类中,并执行默认的初始化操作。如果您显示定义了一个或多个构造器,Java将不会生成默认构造器。
-
**构造器的重载:**类可以在多个构造器,这被称为构造器的重载。重载的构造器可以根据不同的参数进行初始化,允许您以不同的方法创建对象。
-
**初始化对象:**构造器的主要任务是初始化对象的状态,包括设置对象的属性和执行其他必要的初始化操作。在构造器中,您可以对成员变量赋值,调用其他方法,或进行其他操作。
-
**构造器的调用:**构造器在使用
new
关键字创建对象时自动调用。MyClass obj = new MyClass(); // 调用MyClass类的构造器来创建对象
-
**显示调用其他构造器(构造器链):**在构造器中,可以使用
this
关键字来显示调用同一个类中的其他构造器。这被称为构造器链。public MyClass(int value){ // 执行一些初始化操作 } public Myclass() { this(42); // 调用同一个类中的另一个构造器 }
-
**构造器的访问修饰符:**构造器可以具体有访问修饰符,如
public
、private
、protected
或默认(没有修饰符)。访问修饰符决定了构造器的可见性。 -
构造器和继承:子类可以调用父类的构造器来初始化继承的成员变量。在子类的构造器中,可以使用
是
super`关键字调用父类的构造器。public class ChildClass extends ParentClass { public ChildClass(){ super(); //调用父类的构造器 } }
Java 封装
封装(Encapsulation) 是面向对象编程的一个核心概念,它允许将数据和操作数据数据的方法封装在一个单元内,并控制对这些数据和方法的访问。在Java中,封装通过访问修饰符(private
、protected
、public
、默认等)和getter和setter方法来实现。
-
**访问修饰符(Access Modifiers):**Java提供了不同的访问修饰符,用于控制类成员变量和方法的访问权限。
public
:可以被任何类访问。private
:只能被本类内部的方法访问。protected
:可以被子类访问。- 默认(无修饰符):可以被同一个包内的类访问。
-
**成员变量(Instance Variable):**成员变量时类中用于表示对象状态的数据字段。通常应该将成员变量定义为私有(
private
),然后通过getter和setter方法控制对它们的访问。 -
**方法(Methods):**方法是类中的行为或操作。您可以定义公共方法来允许其他类使用类的功能,或者定义私有方法来内部处理数据。
-
**getter方法:**getter方法用于获取对象的成员变量的值。通过以
get
开头,返回成员变量的值。public class Student { private int age; public int getAge(){ return this.name; } }
-
**setter方法:**setter方法用于设置对象的成员变量的值。通常以
set
开头,接收一个参数并将其分配给成员变量。public class Student { private int age; public int getAge(){ return this.name; } public void setAge(int age) { this.age = age } }
-
**封装数据:**通过将成员变量设置为私有,并提供公共的getter和setter方法,可以封装数据,防止直接访问和修改成员变量,从而提高数据的安全性和一致性。
-
**构造器(constructors)😗*构造器是用于初始化对象的方法。构造器可以设置成员变量的初始值,确保对象在创建后处于有效状态。
-
包(Packages): 包使Java中拥有组织和管理类的方式。通过将相关的类放入同一包中,可以控制包对外部类的访问。某些类和成员变量可以被声明为包私有,只能在同一个包内访问。
-
**访问控制:**通过访问修饰符和包的使用,可以实现对类的访问控制,以限制对类的直接访问。
-
**实际应用:**封装的主要目标是隐藏内部实现细节,提供一个清晰的接口供其他代码使用。这有助于减少代码的依赖性,增强代码的可维护性和可重用性。
封装是面向对象编程的重要原则之一,它有助于将复杂性隔离在类内部,提供一种清晰的界面供其他代码使用,同时保护数据的完整性和一致性。在Java中,封装是构架可靠和安全的程序的关键概念之一。
Java 继承
继承(Inheritance)是面向对象编程的核心概念之一,允许一个类(子类或派生类)继承另一个类(父类或基类)的属性和方法。在Java中,继承涉及到许多重要的概念和规则。
- **父类和子类(基类和派生类):**在继承中,一个类可以成为另一个类的父类,而另一个类成为子类。子类继承了父类的属性和方法。
- **extends关键字:**使用
extends
关键字来声明一个类是另一个类的子类。例如,class ChildClass extends ParentClass
表示ChildClass
是ParentClass
的子类。 - **单继承:**Java支持单继承,即一个类只能继承一个父类。这意味着一个类不能同时继承多个父类。
- **父类的成员:**子类继承了父类的成员变量和方法,包括公共和受保护的成员。私有成员不可继承。
- **方法重写(Method Overrding):**子类可以重写(覆盖)父类的方法,以提供自己的实现。方法重写用
@Override
注解来标记,并且必须遵守一定的规则,如方法名、参数列表和返回类型必须相同。 - **super关键字:**在子类中,可以使用
super
关键字来调用父类的构造器和方法。super()
用于调用父类的构造器,super.methodName()
用于调用父类的方法。 - **构造器和继承:**子类可以调用父类的构造器,通常在子类的构造器中使用
super()
来实现。如果没有明确调用父类构造器,Java会自动调用父类的无参构造器。 - **多态性(Polymorphism):**继承和方法重写允许多态性。一个对象可以表现出多个不同的行为,具体取决于实际的对象类型。多态性可以通过父类引用指向子类对象的来实现。
- **final关键字:**使用
final
关键字可以防止类被继承,方法被重写,或成员变量被修改。 - **抽象类(Abstract Class):**抽象类是不能被实例化的类,它可以包含抽象方法。子类必须现实(重写)抽象方法。
- **接口(Interface):**接口是一种特殊的抽象类,它只包含抽象方法和常量。类可以实现接口,实现接口的类必须提供接口中定义的所有方法的实现。
- **方法重载(Method Overloading):**方法重载允许在同一类中定义多个方法,具有相同的名称但不同的参数列表。Java根据 方法参数的数量或类型来选择正确的方法。
- protected关键字:
protected
修饰符允许子类访问父类的受保护成员。受保护成员对于同一个包内的其他类也是可见的。 - **Object类:**所有Java类都直接或间接继承自
java.lang.Object
类。Object
类中包含了一些常见的方法,如equals
、hashCode
和toString
。 - **继承的限制:**子类不能访问父类的私有成员,不能继承构造器,不能同时集成多个类,但可以实现多个接口。
super关键字
super
是Java中的一个关键字,用于引用父类(超类)的成员变量,方法和构造器。super
关键字在继承中扮演了重要的角色,允许子类和父类之间的交互。
-
**引用父类的成员变量:**使用
super
关键字可以在子类中引用父类中的成员变量。这对于访问父类中被子类隐藏的成员变量很有用。class Parent { int num = 10; } class Child extends Parent { int num = 20; void disPlay() { System.out.println("Chind class num:" + num);// 子类的num System.out.println("Parent class num: " + super.num); // 父类的num } }
在上面的示例中,
super.num
引用了父类Parent
中的num
成员变量,而num
引用了子类Child
中的num
成员变量。 -
**调用父类的构造器:**使用
super
关键字可以在子类的构造器中调用父类的构造器。这是因为子类的构造器通常需要初始化冲父类继承的成员变量和执行父类的初始化逻辑。class Parent { int num; Parent(int num){ this.num = num } } class Child extends Parent { int chindNum; Child(int num, int childNum){ super(num); // 调用父类的构造器 this.childNum = childNum; } }
在上面示例中,
super(num)
调用了父类Parent
的构造器,并传递了一个参数num
,以初始化父类的成员变量 -
**调用父类的方法:**使用
super
关键字可以在子类中调用父类中的方法。这在子类需要扩展或修改父类方法的情况下很有用。class Parent { void display() { System.out.println("this is the parent class."); } } class Child extends Parent { @Override void display() { super.display(); // 调用父类的 display方法 System.out.println("This is the child class."); } }
在上面的示例中,
super.display()
调用了父类Parent
的display方法,然后子类Child
在其自己的display
方法中添加了额外的逻辑。super
关键字在继承中用于明确指示引用父类的成员,构造器或方法。通过使用super
子类可以与父类交互并重用父类的功能,同时还可以自定义或扩展自己的行为。这使得继承成为实现代码重用和构建类层次结构的重要机制。
this 关键字
在Java中,this
是一个关键字,用于引用当前对象(实例)。this
关键字在类的方法内部使用,它具有有很多种用途和含义。
-
**引用当前对象:**最常见的用途是引用当前对象,特别是在实例方法内部。它允许在方法中访问当前对象的成员变量和方法。
class MyClass { int number; void setNumber(int number){ this.number = number; // 使用this 引用当前对象的成员变量 } }
在上面的示例中,
this.number
引用了当前对象的number
成员变量。 -
**在构造器中调用其他构造器:**使用
this
关键字可以在一个构造器中调用一个类的其他构造器。这通常用于减少代码冗余和初始化逻辑的重复。class MyClass { int number; MyClass() { this(0); // 调用带有参数的构造器,传递默认值 } MyClass(int number){ this.number = number; // 初始化成员变量 } }
在上面的示例中,无参数构造器使用
this(0)
调用了带参数的构造器来完成初始化。 -
**避免变量名冲突:**当方法参数名与成员变量名相同时,使用
this
关键字可以明确指示引用成员变量而不是方法参数。class MyClass { int number; void setNumber(int number){ this.numer = number; // 使用this引用成员变量,而不是方法参数 } }
-
**在内部类中:**在内部类中,
this
关键字用于引用内部类的当前对象。如果在内部类中存在与外部类相同名称的成员变量,可以使用外部类.this
来引用外部类的成员变量。class OuterClass { int number = 10; class InnerClass { int number = 20; void display() { System.out.println("Inner class number: " + number);// 内部类成员变量 System.out.println("Outer class number: " + OuterClass.this.number); //外部类成员变量 } } }
在上面的示例中,
OuterClass.this.number
引用了外部类OuterClass
的成员变量。总之,
this
关键字在Java中用于引用当前对象,具有多种用途,包括访问当前对象的成员变量和方法,调用其他构造器,避免变量名冲突,以及在内部类中引用外部类的成员。这使得this
成为在类内部引用自身对象的重要工具。
Java 方法重写
方法重写(Method Overriding)是面向对象编程中一个重要概念 ,它允许子类提供其自己的实现来覆盖(重写)从父类继承的方法。在Java中,方法重写具有一些重要的规则和注意事项。
-
**方法签名:**重写的方法在子类中必须与父类中被重写的方法有相同的方法签名。方法签名包括方法的名称、参数列表和返回类型。
-
**@Override 注解:**为了明确表名方法是被重写的,可以使用
@Override
注解在子类中标记重写的方法。这个注解不是强制性,但是建议使用他来提供代码的可读性和可维护性。 -
**访问修饰符:**重写的方法的访问修饰符不能更严格(比如,父类方法是
protected
,子类方法不能是private
)。但是可以更加宽松,例如,父类方法是public
,子类方法可以是public
或protected
. -
**返回类型:**重写的方法是返回类型必须与父类方法的返回类型相同或是其子类型(协变返回类型)。子类方法返回类型是父类方法返回类型对的子类。
-
**抛出的异常:**如果父类方法抛出了受检异常,子类方法可以不抛出,或者只抛出父类方法抛出异常的子类异常。子类方法不能抛出父类方法没有抛出的受检异常。
-
**方法体:**子类的重写方法必须提供自己的实现。这意味着子类方法的方法体与父类方法的方法体不同。在方法体中可以调用父类方法的实现,使用
super
关键字。class Parent { void display() { System.out.println("Parent's display method"); } } class Child extends Parent { @Override void display() { super.display(); // 调用父类方法的实现 System.out.println("Child's display method"); } }
-
**静态方法和final方法:**静态方法和final方法不能被重写。静态方法属于类,而不是实例,而final方法不能子类修改。
-
**构造器和构造器链:**构造器不能被重写,但可以被子类的构造器调用。子类构造器通过
super
关键字调用父类构造器来初始化父类的部分。class Parent { Parent() { // 父类构造器 } } class Child extends Parent { Child() { super(); //调用父类构造器 // 子类构造器 } }
方法重写允许子类提供对父类方法的自定义实现,比满足特定的需求。这是实现多态性的一种方式,因为可以在不改变方法调用的方式的情况下,根据对象的实际类型来调用 适当的方法实现。正确地使用方法重写可以增强代码的灵活性和可扩展性。
Java 多态
多态(Polymorphism)是面向对象编程中的一个重要概念,它允许不同的对象对相同的方法做出不同的响应。多态性是面向对象程序的四大基本特性之一,包括封装、继承和抽象。
在Java中,多态性通常与方法重写(Method Overriding)和接口(Interface)一起使用,以实现一个对象可以以多种不同的方式表现出来的概念。
-
**方法重写:**多态性
class Animal { void makeSound() { System.out.println("Animal makes a sound"); } } class Dog extends Animal { @Override void makeSound() { SYstem.out.println("Dog barks"); } } class Cat extends Animal { @Override void makeSound() { System.out.println("Cat meows"); } } public class PolymorphismExample { public static void main(String[] args){ Animal myPet = new Dog(); // 多态性:父类引用指向子类对象 myPet.makeSound(); // 实际调用的是Dog类的makeSound 方法 } }
-
**多态性的实现:**多态性实现的关键是父类引用(或接口引用)可以指向子类对象。在上面的示例中,
Animal myPet = new Dog()
创建了一个父类引用myPet
,它指向一个子类对象Dog
。这使得可以通过myPet
引用来调用makeSound
方法,实际上调用了Dog
类的方法。 -
**运行时绑定:**多态性在运行时绑定(Runtime Binding)时确定要调用的方法。这意味着编译器不需要知道实际对象的类型,而是在程序运行时根据对象的实际类型来选择方法。
-
**接口和多态性:**多态性还可以通过接口实现。多个类可以实现相同的接口,并且通过接口引用可以调用实现了该接口的类方法。
interface Shape { void draw(); } class Circle implements Shape { @Override void draw() { System.out.println("Drawing a circle"); } } class Rectangle implements Shape { @Ovrride void draw() { System.out.println("Drawing a rectangle"); } } public class PolymorphismExample { public static void main(String[] args){ Shape myShape = new Circle(); //多态性:接口引用指向实际类对象 myShape.draw(); // 实际调用的是Circle类的draw方法 } }
-
**多态性的优点:**多态性提高了代码的灵活性和可维护性。他允许编写通用的代码,不需要为每个具体的子类编写特定代码。这使得代码更容易扩展和修改。
多态性是面向对象编写的核心特性之一,允许以一种更加灵活的方法编写代码,提高了代码的可重用性和可扩展性。通过正确使用方法重写和接口,可以实现多态性的强大效果。
Java instanceof 关键字
instanceof
是Java中的一个关键字,用于测试一个对象是否是指定类的一个实例,或者是否是指定类的子类的一个实例。instanceof
运算符返回一个布尔值(true
或false
),用于确定对象是否与给定的类或接口相兼容。
instanceof
的基本语法输入:
object instanceof Class
object
是要测试的对象。Class
是要检查对象是否是其实例的类或接口。
instanceof
的使用示例:
class Animal { }
class Dog extends Animal { }
public class Example {
public static void main(String[] args){
Animal myAnimal = new Dog();
if (myAnimal instanceof Dog) {
System.out.println("myAnimal is an instance of Dog");
}else if (myAnimal instanceof Animal) {
System.out.println("myAnimal is an instance of Animal");
}else {
System.out.println("myAnimal is not an instance of Dog or Animal");
}
}
}
在上述示例中,myAnimal
是Dog
类的一个实例,因此myAnimal instanceofDog
和 myAnimal instanceof Animal
都返回true
。
instanceof
主要用于一下情况:
-
**类型检查:**检查一个对象是否属于某个特定类或接口。这对于在运行时判断对象的类型很有用,从而采取相应的操作。
-
**避免
ClassCastException
:**在进行类型转换之前,通常使用instanceof
来检查对象是否可以安全地转换为特定类型,以避免ClassCastException
异常。if (myObject instanceof SomeClass) { SomeClass myInstance = (SomeClass) myObject; // 现在可以安全地使用 myInstance } else { // 处理对象无法转换的情况 }
请注意,
instanceof
应该谨慎使用,并且在某些情况下可能表明需要重新考虑类的设计。如果您发现自己频发使用instanceof
来检查对象的类型,可能需要考虑重构代码以便更好地利用多态性和继承。
Java 对象类型转换
Java中,对象类类型转换是指将一个对象引用从一个数据类型转换为另一个数据类型的操作。Java中对象类型转换分为两种类型:向上转型和向下转型。
-
**向上转型(Upcasting):**向上转型是将子类对象引用赋给父类引用的过程。这是一个隐式的,自动的类型转换,因为子类对象可以被看作是父类对象。这个转型是安全的,不需要显式的类型转换。
ParentClass parent = new ChildClass(); // 向上转型
在这个例子中,
ChildClass
是ParentClass
的子类 ,可以将ChildClass
对象赋值给ParentClass
引用变量。 -
**向下转型(Downcasting):**向下转换是将父类对象引用转换为子类对象引用的过程。这是一个显式的类型转换,因为父类对象不能自动视为子类对象。在向下转型时,需要使用强制类型转换符
(类型)
来将父类引用强制转换为子类引用。ParentClass parent = new ChildClass(); ChildClass child = (ChildClass) parent; // 向下转型
在这个例子中,
parent
引用是一个ParentClass
类型的引用,但我们通过强制类型转换将其转换为ChildClass
类型的引用。需要注意的是,向下转型在运行时可能会引发
ClassCastException
异常,因为只有在对象实际属于子类类型的情况下,才能成功进行向下转型。因此,在进行向下转型之前,通常需要使用instanceof
运算符来检查对象的类型以避免异常。ParentClass parent = new ChildClass(); if (parent instanceof ChildClass) { ChildClass child = (ChildClass) parent; //安全的向下转型 } else { // 处理类型不匹配的情况 }
类型转换是Java中处理多态性的关键部分,他允许您根据需要在不同的对象类型之间切换,但需要小心处理向下转型以避免运行时异常。
Java static 关键字
Java中,static
是一个关键字,使用修饰类的成员变量的方法。static
的主要作用是使成员变量和方法与类相关联,而不是与类的实例相关联。
-
**静态成员变量(static Fields):**用
static
修饰的成员变量被称为静态成员变量或类变量。它们属于类而不是类的实例,因此只有一个副本,无论创建多少个类的实例。静态成员变量可以通过类名访问,不需要创建类的实例。class myClass { static int staticVar = 10; }
在上面的示例中,
staticVar
是一个静态成员变量。 -
**静态方法(Static Methods):**用
static
修饰的方法称为静态方法。静态方法也属于类不是实例,可以通过类名直接调用 ,不需要创建类的实例。class MyClass { static void staticMethod() { System.out.println("This is a static method."); } }
在上面的示例中,
staticMethod
是一个静态方法。 -
**静态块(static Blocks):**静态块是一个在类加载时执行的代码块,用于初始化静态成员变量或执行一些静态操作。静态块在类加载是只执行一次。
class MyClass { static { System.out.println("This is a static block."); } }
-
静态导入(static import):
static
关键字还可以用于静态导入,允许您直接访问静态成员变量和方法而不需要使用类名限定。import static java.lang.Math.*; public class MathExample { public static void main(String[] args) { double result = sqrt(25.0); // 直接使用静态导入的 sqrt 方法 System.out.println("Square root of 25 is: " + result); } }
在上面的示例中,
static import
语句允许直接使用sqrt
方法,而不需要使用Math.sqrt
。 -
静态关键字的特点:
- 静态成员变量在类加载时初始化,只有一个副本。
- 静态方法可以通过类名直接调用,不需要创建实例。
- 静态方法啊中不能访问非静态成员变量和方法,但非静态方法可以访问静态成员。
- 静态成员变量通常用于表示类级别的信息,例如常量,计数器等。
- 静态方法通常用于实用方法,如工具类中的方法。
总之,
static
关键字用于创建于类相关联的成员变量和方法,这些成员变量和方法与类的实例无关。静态成员变量在类加载时初始化,静态方法可以通过类名直接调用,而不需要创建类的实例。这使得静态成员变量和方法在多种情况下都非常有用,例如表示常量,实用方法等。
Java 抽象类
Java中,抽象类(Abstract Class)是一种特殊类型的类,它不能被实例化,用于定义一些通用的方法和属性,但这些方法的实现通常是不完整的。抽象类通常用作其他类的基类,子类必须实现抽象类中的抽象方法。
-
**声明抽象类:**使用
abstract
关键字来声明一个抽象类。抽象类可以包含抽象方法和非抽象方法。abstract class Shape { abstract double area(); // 抽象方法 void display() { System.out.println("This is a shape."); } // 非抽象方法 // ... }
在上面的示例中,
Shape
是一个抽象类,它包含了一个抽象方法area()
和一个非抽象方法display()
。 -
**抽象方法:**抽象方法是没有方法体的方法,它只包含方法签名。抽象方法用于强制子类实现自己的具体版本。子类必须提供抽象方法的实现。
abstract double area(); // 抽象方法,没有方法体
-
**子类继承抽象类:**子类可以继承抽象类,并且必须实现父类中的所有抽象方法。如果子类不实现父类的抽象方法,那么子类也必须声明为抽象。
class Circle extends Shape { double radius; Circle(double r) { radius = r; } @Override double area() { return Math.PI * radius * radius; } }
在上面的示例中,
Circle
是一个子类,它继承了Shape
抽象类并实现了area()
抽象方法。 -
**抽象类不能被实例化:**抽象类不能被直接实例化,因为它们通常包含不完整的方法。要创建一个对象,必须使用子类来实例化。
Shape shape = new Circle(5.0); // 使用子类实例化
-
抽象类的作用:
- 定义通用的接口和方法,以确保所有子类都具有相似的行为。
- 强制子类提供特定的实现,以确保方法在子类中正确地执行。
- 可以包含一些共享的代码,以避免在每个子类中重复写相同的代码。
-
**抽象类 vs 接口(interface):**抽象类和接口都可以用于定义抽象方法,但它们有一些不同之处。主要的区别是,抽象类可以包含成员变量和非抽象方法,而接口只能包含抽象方法。类可以继承一个抽象类,但可以实现多个接口。您可以根据具体的需求来选择使用抽象类还是接口。
java 接口
java中,接口(interface)是一种抽象数据类型,它定义了一组抽象方法的规范,但没有提供这些方法的具体实现。接口允许类来实现这些方法,以确保他们遵循接口的约定。
-
**声明接口:**使用
interface
关键字来声明一个接口。interface MyInterface { void method1(); // 抽象方法 int method2(); // 抽象方法 }
在上面的示例中,
MyInterface
是一个接口,它声明了两个抽象方法method1
和method2
。 -
**实现接口:**类可以通过使用
implement
关键字来实现接口。实现接口的类必须提供接口中所有抽象方法的具体实现。class MyClass implements MyInterface { @Override public void method1() { // 提供 method1 的具体实现 } @Override public int method2() { // 提供method2 的具体实现 return 42; } }
在上面的示例中,
MyClass
类实现了MyInterface
接口,并提供了method1
和method2
的实现。 -
**多接口实现:**一个类可以实现多个接口,通过逗号分割。
class MyOtherClass implements Interface1, Interface2 { // 提供接口方法的具体实现 }
-
**默认方法(Default Methods):**Java 8 引入默认方法,允许在接口中提供方法的默认实现。这样,实现接口的类可以选择是否覆盖默认方法。
interface MyInterface { void method1(); default void defaultMethod() { // 提供默认方法的实现 } }
实现类可以选择覆盖
defaultMethod
或者继续使用默认实现。 -
**静态方法(Static Methods):**Java 8 还引入了静态方法,允许在接口中定义静态方法。这些方法可以通过接口名直接调用,而不需要创建接口的实例。
interface MyInterface { static void staticMethod() { // 提供静态方法的实现 } }
-
**接口 vs. 抽象类:**接口与抽象类有一些不同之处。接口可以多重继承,一个类可以实现多个接口,但只能继承一个类。另外,接口中方法都是抽象的,而抽象类可以包含非抽象方法。在设计中,如果一个类需要继承多个类或者需要与其他类共享某些行为,通常使用接口。
Java 内部类
java中,内部类(Inner Class)是定义在另一个类内部的类。内部类具有与外部类(包含它的类)之间的紧密关系,可以访问外部类的成员,包含私有成员。
-
**成员内部类(Member Inner Class):**成员内部类是定义在另一类的内部的类。它可以访问外部类的成员,包括私有成员。
class OuterClass { private int outerField; class InnerClass { void accessOuterField() { System.out.println("Outer field: " + outerField); } } } public class Main { public static void main(String[] args) { OuterClass outer = new OuterClass(); // 创建外部类的实例 OuterClass.InnerClass inner = outer.new InnerClass(); // 使用外部类的实例创建内部类的实例 } }
在上面的示例中,
InnerClass
是一个成员内部类,它可以访问OuterClass
的outerField
。 -
局部内部类(Local Inner Class):局部内部类是定义在方法内部的类,它只在方法内部可见。局部内部类可以访问外部方法的局部变量,但这些变量必须声明
final
class OuterClass { void outerMethod() { final int localVar = 42; class LocalInnerClass { void accessLocalVar() { System.out.println("Local variable: " + localVar); } } LocalInnerClass inner = new LocalInnerClass(); inner.accessLocalVar(); } }
在上面的示例中,
LocalInnerClass
是一个局部内部类,它可以访问outerMethod
中的localVar
变量。 -
**静态内部类(Static Nested Class):**静态内部类是定义另一个内部的静态类,它不需要依赖于外部类的实例而存在。静态内部类不能直接访问外部类的非静态成员。
class Outerclass { private static int staticOuterField; static class StaticInnerClass { void accessStaticOuterField() { System.out.println("Static outer field: " + staticOuterField); } } } public class Main { public static void main(String[] args) { OuterClass.StaticInnerClass inner = new OuterClass.StaticInnerClass(); // 直接创建静态内部类的实例 } }
在上面的示例中,
StaticInnerClass
是一个静态内部类,它可以访问staticOuterField
。 -
**匿名内部类(Anonymous Inner Class):**匿名内部类是一种没有显示类名的内部类,通常用于创建临时的、只在一个地方使用的类。
interface MyInterface { void myMethod(); } public class OuterClass { void useAnonymousInnerClass() { MyInterface anonymousInner = new MyInterface() { @Override public void myMethod() { System.out.println("Anonymous inner class implementation"); } }; anonymousInner.myMethod(); // 在创建对象时实例化匿名内部类 } }
在上面的示例中,创建了匿名内部类来实现
MyInterface
接口的方法。
内部类通常用于实现一种紧密的协作关系,或者封装一个类的辅助功能。选择使用哪种内部类类型取决于具体的需求,但需要注意内部类可能会增加代码的复杂性,因此需要谨慎使用。
Java Error和Exception
Java中,错误(Errors)和异常(Exception)都是处理程序中可能出问题的方法,但它们之间存在重要的却别。
错误(Errors):
- **错误是严重的问题:**错误通常表示系统级的问题,它们严重到无法恢复,例如内存耗尽、虚拟机崩溃等。这些问题通常是由于硬件故障,操作系统问题或其他系统问题引起的,而不由程序错误引起的。
- **不应捕获或处理错误:**通常情况下,不应捕获或处理错误,因为它们通常表示程序无法继续正常执行。如果出现错误,程序应将终止以防止进一步的问题。
- **错误是
java.lang.Errror
类的实例:**Java中的错误被表示为Java.lang.Error
类的实例。一些常见的错误包括OutOfMemoryError
(内存耗尽错误)和StackOverflowError
(栈溢出错误)。 - **错误通常不需要捕获和声明:**在Java中,不需要在方法签名中声明或捕获错误。程序员通常不会自己创建错误,而是由Java运行时系统引发。
异常(Exceptions):
-
**异常是可捕获的问题:**异常表示程序运行中的可预测问题,例如除以零、空指针引用等。这些问题通常由程序员编写的代码引发,因此它们是可预测和可修复的。
-
**异常通常需要捕获和处理:**异常通常需要捕获和处理,以确保程序可以继续正常执行。如果不处理异常,程序将终止并显示错误信息。
-
**异常
java.lang.Exception
类的实例:**Java中的异常被表示为java.lang.Exception
类的实例。异常分为两种主要类型:已检查异常(Checked Exceptions)和未检查异常(Unchecked Exceptions)。- **已检查异常:**通常是由于外部因素(例如文件不存在)引起的问题,必须在方法签名中声明并处理,否则编译器会报错。
- **未检查异常:**通常是由于编程错误(例如空指针引用)引起的问题,不需要在方法签名中声明,但通常需要捕获和处理。
-
**异常处理:**Java提供了异常处理机制,包括使用
try-catch
块来捕获和处理异常,以及使用throws
关键字在方法签名中声明可能抛出的异常。public void exampleMethod() throws SomeException { try { // 可能引发异常的代码 } catch (SOmeException e) { // 处理异常 } }
总结来说,错误表示严重的系统级问题,通常无法恢复,而异常表示可预测的问题,需要捕获和处理以确保程序正常运行。程序员应该小心处理异常,但通常不需要捕获或处理错误。
Java中,Error
和Exception
都是异常类的子类,她们的共同父类是Throwable
。Throwable
类是Java异常处理机制的根类,它是所有异常类的直接或间接父类。Throwable
类定义了一些常用的方法,如getMessage()
、printStackTrace()
等,用于在异常处理中获取有关异常的信息或输出异常的堆栈轨迹。
Java 捕获的抛出异常
Java中,捕获和抛出异常时一种重要的异常处理机制,它允许您在程序中处理异常情况,以确保程序正常运行或者以更合适的方式处理错误。
捕获异常(Catch Exception):
要捕获异常,您可以使用try - catch
块,将可能引发异常的代码放在try
块中,然后在catch
块中捕获并处理异常。
try {
// 可能引发异常的代码
int result = 10 / 0 ; // 这里会引发 ArithmeticException 异常
} catch (ArithmeticException e) {
// 捕获并处理异常
System.out.println("发生了除以零的异常:" + e.getMessage());
}
**多重捕获:**您可以在一个try
块中捕获多个异常类型,以处理不同类型的异常。finally
块用于包裹在try -catch
之后,它中的代码块无论是否发生异常都会被执行。通过用于释放资源或确保某些清理工作得以完成。
try {
// 可能引发异常的代码
} catch (CustomException e) {
// 处理 CustomException 异常
} catch (IOException e) {
// 处理 IOException 异常
} catch (Exception e) {
// 处理其他异常
} finally {
// 执行清理或资源释放操作
}
/* 多重捕获中最下边的应该是范围越大的报错,如果范围大的上面下面可能就不会被触发了
*
*/
上述代码中,我们在try
块中执行除法操作,可能引发ArithmeticException
异常。在catch
块中,我们捕获了该异常并输出了错误信息。
抛出异常(Throw Exception):
有时,您可能需要在代码中手动抛出异常,以表示发生了某种特定情况或错误。您可以使用throw
关键字,用于手动引发异常。你可以使用throw
关键字创建一个异常对象并将其抛出。throws
是一个关键字,用于在方法签名中声明该方法可能抛出的异常类型。这通常用于告诉调用者哪些异常可能在方法执行期间抛出,以便调用者可以选择是否捕获或继续传递这些异常。方法可以声明抛出一个或多个异常,多个异常之间使用逗号分割。声明异常的目的是通知调用者可能需要处理这些异常。
public void someMethod() throws CustomException, IOException {
// 某些条件下抛出自定义异常
if (someCOnditionIsTrue) {
throw new CustomException("发生了自定义异常");
}
}
在上述示例中,我们定义了一个方法someMethod()
,并在其中使用throw
关键字抛出了自定义异常CustomException
。方法的声明中使用throws
关键字指示方法可能抛出此异常。
自定义异常:
您还可以自定义异常类,以便在程序中更好地表示特定的异常情况。自定义异常类通常继承自Exception
或其子类。
public class CustomException extends Exception {
public CustomException(String message) {
super(message);
}
}
在上述示例中,我们 定义了一个自定义异常类CustomException
,它继承自Exception
。该类有一个带有消息的构造函数,允许我们指定异常的详细信息。
总结来说,捕获异常是通过try-catch
块捕获可能反生的异常,而抛出异常时通过throw
关键字手动引发异常。自定义异常允许您更好地表示特定的异常情况,以便在程序中进行适当的处理。异常处理是编写健壮的Java程序的重要组成部分,它可以确保程序在出现问题时能够graceful地处理异常情况。