在Java中,抽象类是一种不能被实例化的类,它主要用于为子类提供一个公共的类型以及可以共享的行为实现。抽象类中可以包含抽象方法(没有具体实现的方法)和非抽象方法(有具体实现的方法)。理解抽象类的概念及其用途对于深入学习Java面向对象编程至关重要。
抽象类
什么是抽象类?
在Java编程语言中,
abstract
关键字用于定义抽象类和抽象方法。抽象类是不能直接实例化的类,它的存在主要是为了被继承。当你预计某些类的子类会有一些共同的属性或行为,但这些行为的具体实现可能因子类而异时,使用抽象类就非常合适了
抽象方法
抽象方法是一种没有具体实现的方法,它只有声明而没有方法体。抽象方法强制子类必须提供具体的实现。在抽象类中定义抽象方法的一般形式如下:
public abstract class AbstractClass {
// 抽象方法
public abstract void someMethod();
}
抽象类的介绍
- 用abstract 关键字来修饰一个类时,这个类就叫抽象类 访问修饰符 abstract 类名{}
- 用abstract 关键字来修饰一个方法时,这个方法就是抽象方法,访问修饰符 abstract 返回类型 方法名(参数列表);//没有方法体
- 抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类()
- 抽象类,是考官比较爱问的知识点, 在框架和设计模式使用较多
定义抽象类
要定义一个抽象类,需要在类的声明前加上
abstract
关键字。抽象类中可以有抽象方法,也可以有非抽象方法。例如:
public abstract class Animal {
String name;
// 抽象方法
public abstract void eat();
// 非抽象方法
public void sleep() {
System.out.println("Zzz...");
}
}
继承抽象类
子类必须覆盖(实现)抽象类中的所有抽象方法,除非子类也是抽象类。这保证了抽象类中定义的接口在子类中得到了具体实现。例如:
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("Dog is eating.");
}
}
为什么使用抽象类?
- 代码复用:抽象类可以提供一些通用的实现,子类可以重用这些实现,减少代码重复。
- 设计模式:在很多设计模式中,如模板方法模式,抽象类用于定义算法的骨架,而将一些步骤延迟到子类中实现。
- 强制一致性:通过要求子类实现特定的抽象方法,确保了所有子类都遵循某种通用的行为规范。
注意事项
- 抽象类不能被实例化,即你不能创建一个抽象类的对象。
- 如果一个类包含了至少一个抽象方法,那么这个类必须声明为抽象的。
- 抽象方法在抽象类中可以不提供实现,但在非抽象子类中必须被实现。
抽象类使用的注意事项和细节讨论
- 抽象类不能被实例化
- 抽家类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法[举
- 一旦类包含了abstract方法,则这个类必须声明为abstract [说明]4) abstract只能修饰类和方法,不能修饰属性和其它的。
- 抽象类可以任意成员【抽象类本质还是类】
- 抽象方法不能有主体
- 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明自己为abstract类
- 抽象方法不能使用private,final和static来修饰
接口
在Java编程语言中,接口(Interface)是一种定义行为的方式,它比抽象类更加抽象和灵活。接口中所有的方法默认都是抽象的(从Java 8开始,接口也可以包含默认方法和静态方法),并且没有任何实现。接口主要用于多个不相关的类之间定义共同的行为标准,从而实现多态性。
基本介绍
interface 接口名{
//属性
//抽象方法
}class 类名 implement 接口{
自己的属性
自己的方法
必须实现的接口的抽象方法
}
定义接口
定义接口的基本语法如下:
public interface MyInterface {
// 常量声明
int CONSTANT = 10;
// 抽象方法声明
void someMethod();
// 从Java 8开始,可以有默认方法
default void defaultMethod() {
System.out.println("This is a default method.");
}
// 从Java 8开始,还可以有静态方法
static void staticMethod() {
System.out.println("This is a static method in an interface.");
}
}
实现接口
类通过使用
implements
关键字来实现接口。如果一个类实现了接口,就必须实现接口中所有的抽象方法(除非该类也是抽象类)。示例:
public class MyClass implements MyInterface {
@Override
public void someMethod() {
System.out.println("Implementing the method defined in the interface.");
}
}
接口的多重继承
Java中的类只能单一继承,但可以实现多个接口,这使得接口成为实现多重继承功能的有效方式。例如:
interface InterfaceA {
void methodA();
}
interface InterfaceB {
void methodB();
}
class MyClass implements InterfaceA, InterfaceB {
@Override
public void methodA() {
// 实现代码
}
@Override
public void methodB() {
// 实现代码
}
}
接口注意事项和细节
- 接口不能被实例化
- 接口中所有的方法是 public 方法, 接口中抽象方法,可以不用 abstract 修饰 .一个普通类实现接口,就必须将该接口的所有方法都实现,可以使用 alt+enter 来解决
- 抽象类去实现接口时,可以不实现接口的抽象方法
使用接口的好处
- 设计原则:接口遵循了设计模式中的“面向接口编程”原则,降低了模块间的耦合度。
- 多态性:实现了接口的类可以被向上转型为接口类型,增加了程序的灵活性和可扩展性。
- 代码重构与维护:接口定义了行为规范,方便未来对代码进行重构和维护,不影响已有的实现类。
- 实现多重继承:虽然Java类不支持多重继承,但通过接口可以达到类似的效果。
内部类
Java中的内部类(Inner Class)是指在一个类的内部定义的另一个类。内部类提供了更好的封装性、访问外部类的成员以及实现复杂逻辑的能力。根据它们的定义位置和作用域的不同,Java内部类主要分为四种类型:成员内部类、局部内部类、匿名内部类和静态嵌套类。下面是对这四种内部类的详细介绍和示例。
成员内部类
成员内部类是最常见的内部类形式,它是外部类的一个成员,如同外部类的字段和方法一样。它可以访问外部类的所有成员,包括私有成员。
public class OuterClass {
private int data = 10;
// 成员内部类
class InnerClass {
void display() {
System.out.println("Data from outer class: " + data);
}
}
// 方法中创建内部类实例并调用
public void showInner() {
InnerClass inner = new InnerClass();
inner.display();
}
}
局部内部类
局部内部类是在方法或代码块中定义的类,它的作用域仅限于该方法或代码块。
public class Outer {
void someMethod() {
class LocalInner {
public void show() {
System.out.println("This is a local inner class.");
}
}
LocalInner li = new LocalInner();
li.show();
}
}
局部内部类的使用
说明:局部内部类是定义在外部类的局部位置,比如方法中,并且有类名。
1.可以直接访问外部类的所有成员,包含私有的
2.不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用
修饰符的。但是可以使用final 修饰,因为局部变量也可以使用final
3.作用域:仅仅在定义它的方法或代码块中。
4.局部内部类﹣-﹣访问﹣--->外部类的成员[访问方式:直接访问]
5.外部类﹣-﹣访问﹣--->局部内部类的成员,访问方式:创建对象,再访问(注意:必须在作用域内)记住:(1)局部内部类定义在方法中/代码块
(2)作用域在方法体或者代码块中
(3)本质仍然是一个类
6.外部其他类﹣-﹣不能访问﹣---->局部内部类(因为 局部内部类地位是一个局部变量)
7.如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.this.成员)去访问 ,System.out.println("外部类的n2=" +外部类名.this.n2);
匿名内部类
匿名内部类没有名字,通常用来创建某个类的子类实例,且只使用一次。它常用于实现接口或继承父类。
interface MyInterface {
void doSomething();
}
public class Test {
public static void main(String[] args) {
MyInterface obj = new MyInterface() {
@Override
public void doSomething() {
System.out.println("Doing something...");
}
};
obj.doSomething();
}
}
静态嵌套类
静态嵌套类(也称为静态内部类)与成员内部类的主要区别在于它不依赖于外部类的实例,可以独立存在。它类似于普通的类,只是碰巧位于另一个类的内部。
public class OuterClass {
static class StaticNestedClass {
void display() {
System.out.println("I am a static nested class.");
}
}
}
public class Main {
public static void main(String[] args) {
OuterClass.StaticNestedClass nestedObj = new OuterClass.StaticNestedClass();
nestedObj.display();
}
}
内部类的使用场景
- 封装性增强:内部类可以访问外部类的私有成员,但外部类无法访问内部类的实现细节,增强了封装性。
- 逻辑组织:当一个类的实现细节仅对另一个类有意义时,可以使用内部类。
- 事件监听和回调函数:匿名内部类广泛应用于实现事件监听器等场景,简化代码结构。
- 单例模式:静态嵌套类常用于实现线程安全的单例模式。
掌握Java内部类的使用,能够让你编写出更加灵活、结构更加清晰的代码。
下期预告--》单例设计模式