8、接口和内部类

接口和内部类

接口

随着软件规模的日益庞大,我们需要把复杂系统划分成小的组成部分,编程接口的设计十分重要。程序设计的实践中,编程接口的设计首先要使系统的职责得到合理划分。良好的接口设计可以降低系统各部分的相互依赖,提高组成单元的内聚性,降低组成单元间的耦合程度,从而提高系统的维护性和扩展性。

1.关于接口的理解。

接口从更深层次的理解,应是定义(规范,约束)与实现(名实分离的原则)的分离。

接口的本身反映了系统设计人员对系统的抽象理解。

接口应有两类:第一类是对一个体的抽象,它可对应为一个抽象体(abstract class);

第二类是对一个体某一方面的抽象,即形成一个抽象面(interface);

一个体有可能有多个抽象面。

抽象体与抽象面是有区别的。

面向接口编程

在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了;而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。

Java接口特性学习

在Java中看到接口,第一个想到的可能就是C++中的多重继承和Java中的另外一个关键字abstract。从另外一个角度实现多重继承是接口的功能之一,接口的存在可以使Java中的对象可以向上转型为多个基类型,并且和抽象类一样可以防止他人创建该类的对象,因为接口不允许创建对象。

interface关键字用来声明一个接口,它可以产生一个完全抽象的类,并且不提供任何具体实现。interface的特性整理如下:

\1. 接口中的方法可以有参数列表和返回类型,但不能有任何方法体。

\2. 接口中可以包含成员变量,但是会被隐式的声明为static和final。public static final

\3. 接口中的成员变量只是被存储在该接口的静态存储区域内,而不属于该接口。

\4. 接口中的方法可以被声明为public或不声明,但结果都会按照public类型处理。

\5. 当实现一个接口时,需要将被定义的方法声明为public类型的,否则为默认访问类型,Java编译器不允许这种情况。

\6. 如果没有实现接口中所有方法,那么创建的仍然是一个接口。

\7. 扩展一个接口来生成新的接口应使用关键字extends,实现一个接口使用implements。

interface在某些地方和abstract有相似的地方,但是采用哪种方式来声明类主要参照以下两点:

\1. 如果要创建不带任何方法定义和成员变量的基类,那么就应该选择接口而不是抽象类。

\2. 如果知道某个类应该是基类,那么第一个选择的应该是让它成为一个接口,只有在必须要有方法定义和成员变量的时候,才应该选择抽象类。因为抽象类中允许存在一个或多个被具体实现的方法,只要方法没有被全部实现该类就仍是抽象类。

以上就是接口的基本特性和应用的领域,但是接口绝不仅仅如此,在Java语法结构中,接口可以被嵌套,既可以被某个类嵌套,也可以被接口嵌套。这在实际开发中可能应用的不多,但也是它的特性之一。需要注意的是,在实现某个接口时,并不需要实现嵌套在其内部的任何接口,而且,private接口不能在定义它的类之外被实现。

如何定义接口?

格式:
[访问修饰符] interface 接口名 [extends 父接口1,父接口2…] {
常量定义 //总是public static final
方法定义 //总是:public abstract
}

如何实现接口

子类通过implements来实现接口中的规范
接口不能创建实例,但是可用于声明引用变量类型。
一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是public的。
Java的类只支持单继承,接口支持多继承

接口相关规则

接口中所有方法都是抽象的。
即使没有显式的将接口中的成员用public标示,也是public访问类型的
接口中变量默认用 public static final标示,所以接口中定义的变量就是全局静态常量。

可以定义一个新接口,用extends去继承一个已有的接口
接口不能继承普通类
可以定义一个类,用implements去实现一个接口中所有方法。
可以定义一个抽象类,用implements去实现一个接口中部分方法。

案例

//接口
package interfacePractect;
public interface UsbInterface {
void power();
}
//实现类
package interfacePractect;
public class Mouse implements UsbInterface {
@Override
public void power() {
System.out.println("插上鼠标");
}
}
//
package interfacePractect;
public class Fan implements UsbInterface{
@Override
public void power() {
System.out.println("插上风扇");
}
}
//
package interfacePractect;
public class UPan implements UsbInterface{
@Override
public void power() {
System.out.println("插上U盘");
}
}
//表现类
package interfacePractect;
public class Computer {
private UsbInterface usb;//将接口变为成员变量
public void func() {
usb.power();//通过接口调用方法
}
//返回值是接口,多态的表现形式
public UsbInterface getUsb() {
return usb;
}
//参数是接口,多态的表现形式
public void setUsb(UsbInterface usb) {
this.usb = usb;
}
}
//测试类
package interfacePractect;
public class Test {
public static void main(String[] args) {
Fan fan = new Fan();
Computer com = new Computer();
com.setUsb(fan);//参数是接口,可以用实现类的引用传递过去
com.func();
}
}

内部类

成员内部类

package out$in;
/**
* 成员内部类 class可以用访问修饰符类修饰访问权限
* 定义在外部类里面,方法外面
* 内部类可以直接使用外部类的成员变量,反之则不行
* 当外部类的成员变量与内部类的成员变量重名时,
* 要想使用外部类的成员变量,则需要通过 外部类名.this.成员变量 来使用
* @author lgx
*
*/
public class OuterClass {
private String name = "外";//外部类成员变量
//成员内部类
class InnerClass{
//内部成员变量
private String name = "内";
//内部成员方法
public void test() {
System.out.println("内部类方法" + OuterClass.this.name);
}
}
public void test() {//外部类成员方法
System.out.println("外部类的成员方法");
}
}
//测试类
package out$in;
import out$in.OuterClass.InnerClass;
/**
* 成员内部类创建对象
* OuterClass oc = new OuterClass();
* InnerClass in = oc.new InnerClass();
* @author lgx
*
*/
public class Test {
public static void main(String[] args) {
OuterClass oc = new OuterClass();
InnerClass in = oc.new InnerClass();
in.test();
oc.test();
}
}

静态内部类

package out$in;
/**
* 静态内部类
* 在外部类里面,方法外面,使用static修饰。
* 当内部类的成员有static时,该内部类必须是静态内部类
* 在外部类的方法使用内部类时,可以直接通过 外部类.内部类 来使用内部的静态成员
* @author lgx
*
*/
public class OuterClass02 {
private int age;
static class InnerClass{
static int age = 20;
String name = "内";
public void test() {
System.out.println("内部类方法");
}
}
public void test() {
System.out.println("外部方法"+OuterClass02.InnerClass.age);
}
}
//测试类
package out$in;
import out$in.OuterClass02.InnerClass;
/**
* 静态内部类创建对象
* 可以直接通过内部类名直接new出来
* InnerClass in = new InnerClass();
* @author lgx
*
*/
public class Test02 {
public static void main(String[] args) {
InnerClass in = new InnerClass();
in.test();
OuterClass02 oc = new OuterClass02();
oc.test();
}
}

方法内部类

package out$in;
/**
* 方法内部类
* 在成员方法里面创建一个类,该内部类只作用于该方法内,出了方法无效
* 所以class前面不能有访问修饰符,也不可以用static修饰,
* 当方法有参数时,参数必须用final修饰
* @author lgx
*
*/
public class OuterClass03 {
private int age;
public void test(final int a) {
class InnerClass{
private int age = 20;
public void test() {
System.out.println("内部类方法"+ a);
}
}
//要想使用内部类的成员变量和方法,必须先创建内部类的对象
InnerClass in = new InnerClass();
in.test();
}
}
//测试类
package out$in;
/**
* 方法内部类不能再其他类中创建对象,因为方法内部类的作用域只在那个方法里面
* @author lgx
*
*/
public class Test03 {
public static void main(String[] args) {
OuterClass03 oc = new OuterClass03();
oc.test(2);
}
}

匿名内部类

//接口
package out$in;
public interface MyInterface {
void test();
}
//测试类
package out$in;
/**
* 匿名内部类
* 适用于只需要使用一次对象的类
* 但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口
*
*
* @author lgx
*
*/
public class Test04 {
public static void main(String[] args) {
//通过接口来接收一个没有名字的类,
//原理是匿名内部类先实现了接口,然后再创建对象
MyInterface mi = new MyInterface() {
@Override
public void test() {
System.out.println("匿名内部类");
}
};
//mi是引用,可以调用里面的方法
mi.test();
}
}

垃圾回收机制

对象空间的分配:

使用new关键字创建对象即可

对象空间的释放:

传统的C/C++语言,需要程序员负责回收已经分配内存。显式回收垃圾回收的缺点:
程序忘记及时回收,从而导致内存泄露,降低系统性能。
程序错误回收程序核心类库的内存,导致系统崩溃。
Java语言不需要程序员直接控制内存回收,是由JRE在后台自动回收不再使用的内存,称为垃圾回收机制(Garbage Collection)。
可以提高编程效率。
保护程序的完整性。
其开销影响性能。Java虚拟机必须跟踪程序中有用的对象,确定哪些是无用的。

垃圾回收机制关键点

垃圾回收机制只回收JVM堆内存里的对象空间。
对其他物理连接,比如数据库连接、输入流输出流、Socket连接无能为力

现在的JVM有多种垃圾回收实现算法,表现各异。
垃圾回收发生具有不可预知性,程序无法精确控制垃圾回收机制执行。
可以将对象的引用变量设置为null,暗示垃圾回收机制可以回收该对象。
程序员可以通过System.gc()或者Runtime.getRuntime().gc()来通知系统进行垃圾回收,会有一些效果,但是系统是否进行垃圾回收依然不确定。

垃圾回收机制回收任何对象之前,总会先调用它的finalize方法(如果覆盖该方法,让一个新的引用变量重新引用该对象,则会重新激活对象)。
永远不要主动调用某个对象的finalize方法,应该交给垃圾回收机制调用。

posted @   站着说话不腰疼  阅读(57)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· Open-Sora 2.0 重磅开源!
点击右上角即可分享
微信分享提示