CSdiy java 05
1 关于java里面的接口
在 Java 中,** 接口(Interface)** 是一种抽象类型,它定义了一组方法的签名(即方法名、参数类型和返回类型),但不包含方法的具体实现。接口主要用于规定类应该具有哪些行为,而不关心这些行为如何实现。它是 Java 中实现多态和代码解耦的重要工具。
核心特点
- 抽象方法:接口中的方法默认是
public abstract
的,只需声明方法签名,无需实现。(就是画一个大饼,别的不需要管很多) - 常量字段:接口中可以定义常量(
public static final
),但不能包含实例变量。 - 多重实现:一个类可以实现多个接口,从而具备多种行为。
- 解耦设计:接口允许将调用逻辑与具体实现分离,提高代码的灵活性和可维护性。
接口 vs 抽象类
特性 | 接口 | 抽象类 |
---|---|---|
方法实现 | 不能有方法体(Java 8 前) | 可以有部分方法实现 |
继承限制 | 支持多实现(一个类可实现多个接口) | 只能单继承(一个类只能继承一个抽象类) |
字段类型 | 只能是public static final 常量 | 可以包含实例变量 |
构造方法 | 没有构造方法 | 可以有构造方法 |
设计目的 | 定义行为规范 | 抽取子类的公共状态和行为 |
接口的使用场景
- 定义规范:例如
Runnable
接口定义了线程执行的规范。 - 回调机制:通过接口实现事件处理(如按钮点击监听)。
- 插件化设计:允许第三方开发者实现接口来扩展功能。
- 多态编程:通过接口类型引用实现类对象,提高代码的通用性。
示例代码
以下是一个简单的接口示例:
java
// 定义接口 Shape
public interface Shape {double getArea(); // 计算面积double getPerimeter(); // 计算周长default void draw() { // Java 8 引入的默认方法System.out.println("绘制形状");}
}// 实现类 Circle
public class Circle implements Shape {private double radius;public Circle(double radius) {this.radius = radius;}@Overridepublic double getArea() {return Math.PI * radius * radius;}@Overridepublic double getPerimeter() {return 2 * Math.PI * radius;}
}// 实现类 Rectangle
public class Rectangle implements Shape {private double width;private double height;public Rectangle(double width, double height) {this.width = width;this.height = height;}@Overridepublic double getArea() {return width * height;}@Overridepublic double getPerimeter() {return 2 * (width + height);}
}
接口的进化(Java 8+)
- 默认方法(Default Methods):Java 8 允许接口中定义带有实现的方法,使用
default
关键字修饰,主要用于扩展接口功能而不破坏现有实现。 - 静态方法:Java 8 支持接口中定义静态方法,用于提供工具功能。
- 私有方法:Java 9 允许接口中定义私有方法,用于封装代码逻辑。
通过接口,Java 实现了对行为的抽象和复用,使得代码可以更加灵活地应对变化。
2 关于implement关键字
在 Java 中,implements
是一个关键字,用于表示一个类实现了某个接口(Interface)。当一个类实现接口时,它需要具体实现该接口中定义的所有抽象方法,从而遵循接口定义的行为规范。
核心概念理解
-
接口(Interface):
接口是一种抽象类型,只包含方法签名(没有方法体)和常量定义。它定义了一组行为规范,但不提供实现细节。 -
实现(Implements):
类通过implements
关键字声明自己遵循某个接口的规范,并提供接口中所有方法的具体实现。 -
语法:
java
public class 类名 implements 接口名1, 接口名2, ... {// 实现接口中的所有抽象方法 }
为什么需要 implements
?
- 多态性:通过接口类型引用实现类的对象,提高代码的灵活性。
- 解耦:将调用逻辑与具体实现分离,便于代码维护和扩展。
- 规范约束:确保类遵循特定的行为契约,强制实现必要的方法。
示例说明
假设我们有一个 Drawable
接口,定义了图形的绘制行为:
java
// 定义接口
public interface Drawable {void draw(); // 抽象方法(默认是 public abstract)
}// 实现类
public class Circle implements Drawable {private double radius;public Circle(double radius) {this.radius = radius;}@Overridepublic void draw() {System.out.println("绘制圆形:半径=" + radius);}
}// 另一个实现类
public class Rectangle implements Drawable {private double width;private double height;public Rectangle(double width, double height) {this.width = width;this.height = height;}@Overridepublic void draw() {System.out.println("绘制矩形:宽=" + width + ", 高=" + height);}
}
关键细节
-
必须实现所有方法:
类必须实现接口中所有的抽象方法,否则该类必须被声明为抽象类。 -
多重实现:
一个类可以同时实现多个接口,用逗号分隔:java
public class MyClass implements Interface1, Interface2, Interface3 {// 实现所有接口的方法 }
-
接口继承:
接口可以继承其他接口,使用extends
关键字:java
public interface Moveable {void move(int x, int y); }public interface Shape extends Drawable, Moveable {double getArea(); // Shape 接口继承了 Drawable 和 Moveable 的方法 }
-
默认方法(Java 8+):
接口中可以定义默认方法(使用default
关键字),实现类可以选择重写或直接使用:java
public interface Drawable {void draw(); // 抽象方法default void printInfo() {System.out.println("这是一个可绘制的对象");} }
实际应用场景
- 事件监听:如
ActionListener
接口。 - 数据结构:如
List
、Set
接口。 - 线程编程:如
Runnable
接口。 - 插件系统:通过接口定义扩展点。
通过 implements
,Java 实现了对行为的抽象和复用,使代码更具灵活性和可维护性。
3 this ? 初始化 ?
this
关键字的作用
this
在这里不是初始化。在 Java 中,this
关键字有以下主要作用:
- 区分成员变量和局部变量:当方法参数名或局部变量名与类的成员变量名相同时,使用
this
可以明确指定访问的是类的成员变量。比如在box
方法和构造函数中,width
、height
、color
既是方法参数,类中又有同名成员变量,this.width
、this.height
、this.color
就是用来指向类的成员变量,将参数值赋给对应的成员变量 。 - 在构造函数中调用其他构造函数(这里未涉及):可以使用
this(参数列表)
的形式在一个构造函数中调用本类的其他构造函数。
this
本身不能直接等同于初始化操作 ,但在构造方法等场景中会参与对象成员变量的初始化相关过程:
- 区分变量:像前面代码中,
this.width = width;
等语句,this
主要是用来区分同名的成员变量和局部变量(方法参数),将传入的参数值赋给对象的成员变量,间接实现成员变量初始状态的设定。 - 调用构造方法:在一个类的构造方法中,可使用
this(参数列表)
来调用本类的其他构造方法,辅助完成对象更复杂的初始化设置。例如:
java
public class Example {private int num;private String str;public Example(int num) {this.num = num;}public Example(int num, String str) {this(num); // 调用上面的构造方法,先初始化numthis.str = str;}
}
所以,this
不是单纯意义上的初始化动作,但在对象初始化过程中起到重要辅助作用。
4 什么时候会要求有声明返回值类型?
在 Java 等编程语言中,以下情况要求声明返回值类型:
普通方法
当方法执行特定功能后,会产生一个结果需要反馈给调用者时,必须声明返回值类型。比如计算两个整数和的方法 int add(int a, int b)
,明确声明返回值类型为 int
,方法体内通过 return
语句返回计算结果,调用者就能获取到相加后的数值。
接口中的抽象方法
接口定义一组规范,其中的抽象方法需声明返回值类型,由实现该接口的类去具体实现该方法并按要求返回对应类型的值 。例如定义接口 interface Shape { double getArea(); }
,实现类如 Circle
类,就要实现 getArea
方法并返回正确的 double
类型的面积值。
类中的非构造方法
除构造方法(构造方法无返回值类型声明)外,类中定义的其他方法若要返回数据给调用处,都得声明返回值类型。像获取用户信息的方法 User getUserInfo()
,声明返回值类型为自定义类 User
,执行后能将封装好的用户信息对象返回。
总之,只要方法执行后有数据要传递给调用者,就需要在方法声明时指定返回值类型,以保证类型安全和程序逻辑正确。
5 小小的void,大大的区别
方法类型和作用
public void box(int width, int height, Color color)
:这是普通的成员方法 。它的作用是通过传入的参数来设置对象的相关属性(这里应该是设置当前类中名为width
、height
、color
的属性 ),但不返回任何值。在程序中,通常用于执行特定的操作,比如对对象状态进行修改等。public Rectangle(int width, int height, Color color)
:这是构造函数 。构造函数的特殊之处在于,它的名字必须与类名相同,且没有返回值类型声明(包括不能写void
)。它在使用new
关键字创建Rectangle
类的对象时自动调用,用于对新创建的对象进行初始化,比如给对象的属性赋予初始值。
调用方式
- 普通成员方法:需要通过类的对象来调用,比如
对象名.box(参数值)
。 - 构造函数:在使用
new Rectangle(参数值)
创建对象时自动被调用,不能像普通方法那样直接调用。
6 编译器提示将字段转换为局部变量
作用域相关
- 减少不必要的作用域污染:字段(类成员变量)作用域是整个类,生命周期伴随对象存在。而局部变量作用域仅在定义它的方法、代码块内 。如果一个变量仅在类中某个方法内使用,定义为字段会让它在整个类中可见,增加了命名空间的复杂度。转换为局部变量,能让变量作用域更精准,减少命名冲突风险,也让代码逻辑更清晰,只在真正使用的地方存活。
内存管理相关
- 优化内存占用:字段在对象创建时就分配内存,直到对象被垃圾回收才释放。局部变量在进入其作用域时分配内存,离开作用域就释放。若一个变量使用场景局限在方法内,作为局部变量可及时释放内存,尤其在频繁调用方法的场景下,能减少内存占用,提高程序性能。
代码维护相关
- 增强代码可读性和可维护性:局部变量与所在方法逻辑关联更紧密,将仅在方法内使用的字段转换为局部变量,能让代码阅读者更直观理解变量用途和生命周期,维护时也更容易定位和修改相关逻辑。