Java访问修饰符与接口的深入解析
1. Java访问修饰符概述
在Java编程中,访问修饰符是控制类、方法和字段访问权限的重要工具。主要的访问修饰符有
private
、默认(无修饰符)、
protected
和
public
,它们的访问权限由严格到宽松依次排列。下面详细介绍不同访问修饰符的特点和使用场景。
2. 默认访问(Default Access)
默认访问是指在声明类、方法或字段时不使用任何访问修饰符。在许多示例中,默认访问很常用,因为它避免了理解
public
和
private
的复杂性,减少了需要关注的关键字。然而,在实际编程中,程序员通常会避免使用默认访问。因为使用默认访问时,同一包中的所有其他类都可以查看和修改字段的值,这可能导致数据被意外修改。例如,其他程序员可能会将
daysInThisMonth
设置为32,或者将
chaptersInThisBook
设置为 -7。因此,最好的策略是仅在绝对必要时使用默认访问。在大多数情况下,如果其他类需要获取或设置字段的值,应该使用
private
访问,并提供
public
的getter和setter方法。
3. 受保护访问(Protected Access)
很多人初次接触Java时,可能会认为
protected
意味着安全可靠。但实际上,在Java中,受保护的成员比具有默认访问权限的成员更不隐蔽、更不安全,并且可以在更多的类中使用。也就是说,
protected
访问比默认访问更宽松。
-
不同包中的子类
:当一个字段具有默认访问权限时,它只能在其所在的包内被访问。但如果在字段声明前添加
protected
关键字,那么该字段所在包之外的子类就可以访问它。例如,以下代码展示了
Drawing
类和它的子类
DrawingWide
:
// Listing 14-8: Protected Fields
package com.burdbrain.drawings;
import java.awt.Graphics;
public class Drawing {
protected int x = 40, y = 40, width = 40, height = 40;
public void paint(Graphics g) {
g.drawOval(x, y, width, height);
}
}
// Listing 14-9: The Subclass from the Blue Lagoon, Part II
import java.awt.Graphics;
import com.burdbrain.drawings.Drawing;
public class DrawingWide extends Drawing {
int width = 100, height = 30;
public void paint(Graphics g) {
g.drawOval(x, y, width, height);
}
}
在
Drawing
类中,
x
、
y
、
width
和
height
字段被声明为
protected
。
DrawingWide
类有自己的
width
和
height
字段,但它可以引用父类
Drawing
中定义的
x
和
y
字段,即使
DrawingWide
与
Drawing
不在同一个包中。这是因为
x
和
y
字段在
Drawing
类中是受保护的。
-
同一包中的非子类
:受保护的成员不仅可以被不同包中的子类访问,还可以被同一包中的非子类访问。例如,以下代码展示了
ShowFrameWideBB
类如何访问
Drawing
类的受保护字段:
// Listing 14-10: Drawing a Wider Oval
package com.burdbrain.drawings;
import com.burdbrain.frames.ArtFrame;
class ShowFrameWideBB {
public static void main(String args[]) {
Drawing drawing = new Drawing();
drawing.width = 100;
drawing.height = 30;
ArtFrame artFrame = new ArtFrame(drawing);
artFrame.setSize(200, 100);
artFrame.setVisible(true);
}
}
ShowFrameWideBB
类与
Drawing
类在同一个包中,但它不是
Drawing
类的子类。由于
Drawing
类中的字段是受保护的,
ShowFrameWideBB
类可以顺利访问和修改这些字段的值。
4. 不同访问修饰符的权限对比
| 访问修饰符 | 同一类 | 同一包中的子类 | 同一包中的非子类 | 不同包中的子类 | 不同包中的非子类 |
|---|---|---|---|---|---|
private
| √ | × | × | × | × |
| 默认 | √ | √ | √ | × | × |
protected
| √ | √ | √ | √ | × |
public
| √ | √ | √ | √ | √ |
5. Java类的访问修饰符
Java类的访问修饰符相对简单,类可以是
public
或非
public
的。
-
公共类(Public Classes)
:如果一个类是
public
的,那么在代码的任何地方都可以引用该类。但需要遵守目录结构规则,并正确引用打包的类。例如:
import com.burdbrain.drawings.Drawing;
import com.burdbrain.frames.ArtFrame;
ArtFrame artFrame = new ArtFrame(new Drawing());
或者不使用
import
声明:
com.burdbrain.frames.ArtFrame artFrame = new com.burdbrain.frames.ArtFrame(new com.burdbrain.drawings.Drawing());
-
非公共类(Nonpublic Classes)
:如果一个类不是
public的,那么只能在该类所在的包内的代码中引用它。例如,将Drawing类的public关键字删除后,同一包中的DrawingWideBB类可以访问它,但不同包中的类则无法访问:
// 修改后的Drawing类
package com.burdbrain.drawings;
import java.awt.Graphics;
class Drawing {
public int x = 40, y = 40, width = 40, height = 40;
public void paint(Graphics g) {
g.drawOval(x, y, width, height);
}
}
// 同一包中的DrawingWideBB类可以访问
package com.burdbrain.drawings;
public class DrawingWideBB extends Drawing
// 不同包中的类无法访问
package com.burdbrain.frames;
// 会报错
Drawing drawing;
6. 实践建议
-
在实际编程中,尽量使用
private访问修饰符来保护类的字段,避免数据被意外修改。 -
当需要让不同包中的子类访问某些成员时,可以使用
protected访问修饰符。 -
对于需要在整个项目中被广泛使用的类,使用
public访问修饰符。
7. 操作尝试
-
在
Listing 14-2中画一个圆,若要将圆填充为绿色,可以使用Graphics类的setColor和fillOval方法:
g.setColor(Color.GREEN);
g.fillOval(x, y, width, height);
其中,
Color.GREEN
属于
java.awt
包中的
Color
类。
- 创建一个显示交通信号灯的框架,包含绿色、黄色和红色灯。
- 定义
Book
类和
Author
类,
Book
类有标题和作者,
Author
类有姓名和一个
Book
实例的
ArrayList
。创建一个包含
main
方法的类,创建多个书籍和作者实例,并显示相关信息。将每个类放在不同的包中,尽可能将字段设为
private
,并提供
public
的getter和setter方法。
- 定义
Item
类、
Artist
类、
Song
类、
Album
类和
Playlist
类。
Item
类有名称和艺术家,
Artist
类有姓名和一个
Item
实例的
ArrayList
。
Song
类和
Album
类是
Item
类的子类,
Song
类有一个
Genre
枚举类型的属性,
Album
类有一个
Song
实例的
ArrayList
,
Playlist
类有一个
Item
实例的
ArrayList
。创建这些类的实例,并在屏幕上显示相关信息。
- 分析以下四个类的代码,判断哪些语句会导致IDE显示错误信息,并确定消除错误信息所需的最小权限更改:
// THIS CODE DOES NOT COMPILE:
package com.allmycode.things;
import com.allyourcode.stuff.Stuff;
import com.allyourcode.stuff.morestuff.MoreStuff;
public class Things {
protected int i = 0;
private int j = 0;
int k = 0;
public static void main(String[] args) {
Stuff stuff = new Stuff();
System.out.println(stuff.i);
MoreStuff moreStuff = new MoreStuff();
System.out.println(moreStuff.i);
}
}
package com.allyourcode.stuff;
import com.allyourcode.stuff.morestuff.MoreStuff;
public class Stuff {
protected int i = 0;
void aMethod() {
new MoreStuff().myMethod();
}
}
package com.allyourcode.stuff.morestuff;
import com.allmycode.things.Things;
public class MoreStuff extends Things {
protected void myMethod() {
System.out.println(i);
}
}
package com.allmycode.things;
public class MoreThings extends Things {
public void anotherMethod() {
System.out.println(i);
System.out.println(j);
System.out.println(k);
}
}
通过以上内容,我们对Java的访问修饰符有了更深入的了解,合理使用访问修饰符可以提高代码的安全性和可维护性。在后续的编程中,我们可以根据具体需求选择合适的访问修饰符来控制类和成员的访问权限。
Java访问修饰符与接口的深入解析
8. Java的引用类型
Java有两种类型:
-
基本类型
:Java有八种基本类型,常用的四种是
int
、
double
、
boolean
和
char
。
-
引用类型
:Java的API有数千种引用类型,在编写Java程序时,还可以定义新的引用类型。例如
String
、
Scanner
、
JFrame
、
ArrayList
、
File
等都是引用类型,自定义的类也是引用类型,并且每个数组也属于引用类型。
9. Java接口
-
接口的概念
:类和子类之间是继承关系,如
FullTimeEmployee类继承Employee类。而接口则是一种类似契约的机制。一个类可以实现多个接口,接口规定了实现类必须提供的方法。例如,一个人可以是Person类的实例,同时实现Professor接口和Author接口,那么这个人必须有teachStudents、adviseStudents、gradePapers、writeChapters、reviewChapters、answerEmail等方法。 - 接口的声明 :接口中的方法通常是抽象方法,只有方法头,没有方法体。以下是两个接口的声明示例:
// Listing 15-1: Behold! An Interface!
public interface Displayable {
public void display();
}
// Listing 15-2: Another Interface
public interface Summarizable {
public String summarize();
}
-
接口的实现
:类实现接口时,必须为接口中的抽象方法提供具体的实现。以下是实现
Displayable和Summarizable接口的示例:
// Listing 15-3: Implementing Two Interfaces
public class ColumnOfNumbers implements Displayable, Summarizable {
double numbers[];
public ColumnOfNumbers(double[] numbers) {
this.numbers = numbers;
}
@Override
public void display() {
for (double d : numbers) {
System.out.println(d);
}
}
@Override
public String summarize() {
double total = 0.0;
for (double d : numbers) {
total += d;
}
return Double.toString(total);
}
}
// Listing 15-4: Another Class Implements the Interfaces
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
public class Table implements Displayable, Summarizable {
Scanner diskFile;
ArrayList<String> lines = new ArrayList<>();
public Table(String fileName) {
try {
diskFile = new Scanner(new File(fileName));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
while (diskFile.hasNextLine()) {
lines.add(diskFile.nextLine());
}
}
@Override
public void display() {
for (String line : lines) {
System.out.println(line);
}
}
@Override
public String summarize() {
return lines.get(0);
}
}
在上述代码中,使用了
@Override
注解来表明这是对接口方法的实现。
10. 接口的使用示例
以下代码展示了如何使用实现了接口的类:
// Listing 15-5: Getting the Most out of Your Interfaces
public class Main {
public static void main(String[] args) {
double numbers[] = { 21.7, 68.3, 5.5 };
ColumnOfNumbers column = new ColumnOfNumbers(numbers);
displayMe(column);
summarizeMe(column);
Table table = new Table("MyTable.txt");
displayMe(table);
summarizeMe(table);
}
static void displayMe(Displayable displayable) {
displayable.display();
System.out.println();
}
static void summarizeMe(Summarizable summarizable) {
System.out.println(summarizable.summarize());
System.out.println();
}
}
在这个示例中,
displayMe
方法和
summarizeMe
方法只关心参数是否实现了相应的接口,而不关心具体的类。这体现了接口的强大之处,提高了代码的灵活性和可扩展性。
11. 实践拓展
-
创建
Deletable接口,任何实现该接口的类必须有delete方法。 -
创建
DeletableColumnOfNumbers类,它是ColumnOfNumbers类的子类,同时实现Deletable接口。当删除一列数字时,将每个元素的值设为0.0。 -
创建
DeletableTable类,它是Table类的子类,同时实现Deletable接口。当删除一个表时,移除除第一行(表头)之外的所有行。
12. 总结
-
Java的访问修饰符包括
private、默认、protected和public,合理使用它们可以控制类和成员的访问权限,提高代码的安全性和可维护性。 - Java接口为类提供了一种实现多态的方式,通过实现接口,类可以具备不同的行为,增强了代码的灵活性和扩展性。
以下是一个简单的流程图,展示了类、接口和实现类之间的关系:
graph TD;
A[类] -->|继承| B[子类];
C[接口1] -->|实现| D[实现类];
E[接口2] -->|实现| D[实现类];
在实际编程中,可以根据这些知识,设计出更加合理、高效的Java程序。例如,在设计一个大型系统时,可以使用接口来规范不同模块之间的交互,使用访问修饰符来保护关键数据和方法。同时,多进行实践操作,加深对这些概念的理解和掌握。
超级会员免费看
35

被折叠的 条评论
为什么被折叠?



