java中接口的使用

       一般使用接口隔离具体实现,可以将类之间的相互依赖变为类对接口的依赖。例如出差类和会飞的东西 是通过会飞的接口进行隔离,这样不管出差类需要修改或者会飞的东西需要修改,都不会相互影响。
如果一组相关的类中有公共的方法和特殊的方法,可以使用抽象类,在抽象类中固化公共的方法【算法 骨架】,而无需具体子类重复实现;但是在抽象类中无法实现的方法可以延迟到子类中再实现。例如排 序器BubbleSorter ,其中抽象类 BubbleSorter 固化了所使用的冒泡排序算法,而将无法实现的 bigger 比 较算法延迟到BubbleSorter 的子类 PigSorter 中实现,同时 PigSorter 中也不需要重新定义排序算法。
最佳软件开发实践:先定义接口规范调用方法,在使用抽象类实现接口定义公共方法,最后再定义具体 子类实现所有的方法。
接口和抽象类的使用场景
       从设计层面看,抽象类体现继承关系 is a ,它主要描述类的从属关系或者父子关系,抽象类和它的派生类 之间是典型的IS-A 关系,即子 is a 父。
interface 可以多实现,而且不要求实现者和 interface 定义在概念本质上是一致的,仅仅是实现了
interface 定义的契约而已。它主要描述的是类型间的行为合同,接口和它的实现类之间是典型的 CANDO关系,即子 can do 父。
         为什么接口需要默认方法
     在接口添加默认方法不需要修改实现类,接口新增的默认方法在实现类中直接可用。
另外还要注意默认方法冲突问题。
内部类
一个类或者接口定义在另外一个类后者接口的内部
public class A1{//外部类
class B1{}//内部类
interface C1{}//内部接口
}
将一个类定义置入另一个类定义中,这就叫作 内部类
内部类之外的类称为外部类
内部类的名称必须区别于它所在的外部类,和其它类之间没有要求
内部类的全名叫做[外部类名称$内部类名称]
public class A1 {
public class A1{} //语法报错
class B1{} 语法正确,默认编译的结果名称为A1$B1.class
}
class B1{}
内部类可以访问其外部类的所有变量和方法
public class A1 {//外部类的范围限定词只能是public或者默认package
private String name;
public class B1 { //内部类的范围限定词可以是4种
public void pp() {
System.out.println(name);
System.out.println(A1.this.name);//这里的A1.this用于表示A1类对
象
A1.this.name="ffff";
// System.out.println(this.name);报错的原因是this用于指代当前类
的对象,当前类B1中并没有属性name
pp();
A1.this.pp();
}
}
private void pp(){}
}
外部类不能直接访问内部类的实现细节
public class A1 {
private String name;
public class B1 {
private int age=99;
public void ff() {
System.out.println(name);
System.out.println(A1.this.name);
A1.this.name="ffff";
}
private void dd(){}
}
private void pp(){
B1 b=new B1(); //如果需要在外部类中访问内部类的实现细节则需要构建内部类
对象,然后通过内部类对象进行访问
b.ff();
System.out.println(b.age); //注意:可以直接访问内部类中的私有属性
b.dd();//私有方法仍旧可以直接调用
}
}

内部类比外部类多了 private/protected/static 三个修饰符,这三个修饰符不能用在外部类上
非静态内部类不能拥有静态成员
protected class B1 {
private int age = 99;
{ }//允许包含非静态代码块
private static String password="123456";//非静态内部类中不能包含静态属
性
static{ }//非静态内部类中不允许包含静态代码块
public B1() {//允许定义构造器和析构器方法
}
public static void hh(){} //非静态内部类中不允许包含静态方法
内部类的作用
内部类提供更好的封装
内部类可以直接访问外部类的私有成员
外部类不能直接访问内部类的成员,需要构建内部类对象才能访问
匿名内部类适合用于创建仅仅使用一次使用的类
内部类相关的设计
分析事物时发现该事物描述还有事物,而且这个事物还在访问被描述事物的内容
例如牛和牛腿
如果一个事物离开另外一个事物后则没有任何意义,这种情况下建议使用内部类,不允许其他类访
内部类能直接访问外部类中成员,是因为内部类持有了外部类的引用,即外部类名 .this
内部类分类
Java 中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的
内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。
内部类实际拥有外部类的一个引用,在构造函数中将外部类的引用传递进来。
非静态内部类
基础语法
public class A1{
protected class B1{}//静态内部类是protected static class B1{}
}
非静态内部类的特点:
和其他类一样,它只是定义在外部类中的另一个完整的类结构
可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无
可以在非静态内部类中声明属性、方法、构造器等结构,但是不允许声明静态成员,但是可以
继承父类的静态成员,而且可以声明静态常量。
可以使用 abstract 修饰,因此它也可以被其他类继承
可以使用 final 修饰,表示不能被继承
编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名和 $ 符号。
和外部类不同的是,它可以允许四种权限修饰符: public protected ,缺省, private
外部类只允许 public 或缺省的
还可以在非静态内部类中使用外部类的所有成员,哪怕是私有的
在外部类的静态成员中不可以使用非静态内部类哦
就如同静态方法中不能访问本类的非静态成员变量和非静态方法一样
在外部类的外面必须通过外部类的对象才能创建非静态内部类的对象
因此在非静态内部类的方法中有两个 this 对象,一个是外部类的 this 对象,一个是内部类的
this 对象
在创建非静态内部类对象时,一定要先创建起相应的外部类对象
public class A1 {
public static void main(String[] args) {
B1 b = new B1();
B1.C1 cc = b.new C1(); //内部类的写法为[外部类名.内部类名],否则需要
import com.yan.B1.C1;则可以直接使用C1类。至于C1类是否可见取决于C1类的范围限定词
System.out.println(cc);
}
}
class B1 {
public class C1 {
}
}

在任何非静态内部类中,都不能有静态数据、静态方法或者又一个静态内部类
语法错误
public class A1{
public class B1{
public static String name="yan";//语法错误,除非B1类是静态内部类
static class B1{}
static{}//语法错误
public static void pp(){}//语法错误
public static class C1{}//语法错误
}
}

注意内部类的可见性范围限制
访问方法:直接访问外部类中内部类中的成员
class B1 {
private String pwd;
private void dd(){}
protected class C1 {
private String name;
private void pp(){
System.out.println(pwd);//内部类可以直接访问外部类中的私有成
员
//另外的写法 B1.this.pwd
dd();
//另外的写法 B1.this.dd();
}
}
public void ee(){
//如果需要访问内部类中的成员,则必须首先创建内部类对象
C1 cc=new C1();
//通过构建的内部类对象则可以访问内部类中的私有成员
cc.name="abc";
cc.pp();
}
}

外部类 . 内部类 in=new 外部类 ().new 内部类 ()
public class A1 {
public static void main(String[] args) {
B1 b = new B1();
B1.C1 cc=b.new C1();//内部类是否可以访问到,取决于内部类上的范围限
定词
}
}
class B1 {
class C1{}
}
in. 内部类方法 ();
public class A1 {
public static void main(String[] args) {
B1 b = new B1();
B1.C1 cc=b.new C1();
cc.pp(); //是否可以访问pp方法取决于pp方法的范围限定词
}
}
class B1 {
class C1{
public void pp(){}
}
}
注意内部类的可见性范围限制
class B1 {
private class C1{//注意这个C1类只能在B1类中进行使用,其它位置不可见
public void pp(){}
}
}
问题:
public class A1 {
public A1(){
System.out.println("aaaaa");
}
public static void main(String[] args) {
new A1();//创建外部类对象和内部类无关,创建外部类对象并不会自动创建内
部类对象
}
class C1 {
public C1() {
System.out.println("dddd");
}
}
}
静态内部类
基础语法
public class A1{
public static class B1{}//静态内部类
}
静态内部类的特点:
和其他类一样,它只是定义在外部类中的另一个完整的类结构
可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无
可以在静态内部类中声明属性、方法、构造器等结构,包括静态成员
可以使用 abstract 修饰,因此它也可以被其他类继承
可以使用 final 修饰,表示不能被继承
编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名和 $ 符号。
和外部类不同的是,它可以允许四种权限修饰符: public protected ,缺省, private
外部类只允许 public 或缺省的
可以在静态内部类中使用外部类的 静态成员
在静态内部类中不能使用外部类的非静态成员哦
在外部类的外面不需要通过外部类的对象就可以创建静态内部类的对象
如果在内部类中有变量与外部类的静态成员变量同名,可以使用 外部类名 ." 进行区别
静态内部类中,可以有静态数据、静态方法或者又一个静态内部类
class B1 {
static class C1 {// 在静态内部类中才可以定义静态成员
private static int age = 123;
private String pwd="123456";//同时允许定义非静态成员
static {
System.out.println("c1 static...");
}
public static void pp() {
System.out.println("c1 static pp...");
}
public void ff(){//同时允许定义非静态成员
}
static class D1{}
class E1{}
}
}
如何使用静态内部类
public class A1 {
public static void main(String[] args) {
B1.C1 cc = new B1.C1();//不需要构建外部类对象,就可以直接创建静态内部类对
象,但是是否可见取决于范围限定词
B1.C1.pp();//可以直接访问静态内部类中的静态成员,但是是否可见取决于范围限定
词
cc.ff();
}
}
问题
public class A1 {
public static void main(String[] args) {
B1.C1 cc = new B1.C1();
}
}
class B1 {
private B1() {
System.out.println("bbbbbb");
}
static class C1 {// 在静态内部类中才可以定义静态成员
public C1() {
System.out.println("cccccc");
}
static {
System.out.println("c1 static...");
}
输出只有
c1 static... 类加载完成后自动执行
cccccc 构建静态内部类对象和外部类无关,没有要求必须先构建外部类对象

静态内部类中,也可以有非静态数据、非静态方法或者又一个非静态内部类
静态内部类中,不能访问外部类的非静态成员,这是由 Java 语法中【静态方法不能直接访问非静态
成员】所限定
class B1 {
private static String name1 = "yan1";
private double salary = 123.456;
static class C1 {
private static int age = 123;
private String pwd = "abc";
public static void pp() {
System.out.println(age);// 静态方法只能访问静态成员
// System.out.println(this.age);在靜態方法中不允許使用this或者
super
// System.out.println(pwd); 语法报错
System.out.println(name1);// 静态内部类中可以直接访问外部类中的静
态成员
dd();
// System.out.println(salary);语法报错,因为静态方法只能访问静态成
员
}
public void fff() {
System.out.println(this.age);
System.out.println(pwd);//当前类中的非静态成员
System.out.println(name1);// 不允许使用B1.this或者this.进行访
问,不允许使用B1.this是因为构建C1类对象时没有要求必须构建外部类对象
// System.out.println(salary);报错的原因是构建构建C1类对象时没有
要求必须构建外部类对象
dd();
// ee();z直接访问ee方法报错,构建构建C1类对象时没有要求必须构建外部类
对象
}
}
private void ee() {
}
private static void dd() {
}
}
class B1 {
static class C1 {
}
}
构建内部类对象的方法:
B1.C1 cc = new B1.C1();
以下创建方法错误:
B1 b = new B1();
B1.C1 c = b.new C1();
public class A1 {
public static void main(String[] args) {
B1.C1 bcc=new B1.C1();
}
}
class B1 {
private static D1 dd=new D1();
static {
System.out.println("B1 static....");
}
static class C1 {
private static E1 dd=new E1();
static {
System.out.println("C1 static...");
}
}
}
这里执行会发现B1类的静态代码块和静态属性并没有执行处理,所以要理解外部类实际上是内部类
的一个名空间。加载内部类时实际上并没有加载外部类----重点

局部内部类
可以将内部类定义在一个方法或者一个代码块内
public class A1 {
private int age = 123;
public static void main(String[] args) {
A1 aa = new A1();
}
public void pp() {
Date birth = new Date();
// B1 bb=new B1();语法错误,要求局部内部类必须先定义后使用
class B1 { // 局部内部类,只能在所在的{}范围中使用,具备内部类的范围限定词和临
时变量一致,只能添加final或者abstract
public void ff() {
System.out.println(age);
A1.this.age = 555;// 可以直接访问外部类中的成员
System.out.println(birth);
// 语法报错,在局部内部类中使用外部的临时变量,则外部临时变量必须是
final的,只是final可以省略
// birth = new Date();针对引用类型修改地址是不允许,但是可以修改属性
System.out.println("B1...ff()");
}
}
B1 bb = new B1();
}
}

局部内部类的特点:
和外部类一样,它只是定义在外部类的某个方法中的另一个完整的类结构
可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无
可以在局部内部类中声明属性、方法、构造器等结构, 但不包括静态成员,除非是从父类继承
的或静态常量
可以使用 abstract 修饰,因此它也可以被同一个方法的在它后面的其他内部类继承
可以使用 final 修饰,表示不能被继承
编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名、 $ 符号、编号。
这里有编号是因为同一个外部类中,不同的方法中存在相同名称的局部内部类
和成员内部类不同的是,它前面不能有权限修饰符等
局部内部类如同局部变量一样,有作用域
局部内部类中是否能访问外部类的静态还是非静态的成员,取决于所在的方法
局部内部类中还可以使用所在方法的局部常量,即用 final 声明的局部变量
JDK1.8 之后,如果某个局部变量在局部内部类中被使用了,自动加 final
问题:
public class A1 {
private int age = 123;
public static void main(String[] args) {
A1 aa = new A1();
}
public void pp() {
Date birth = new Date();
// B1 bb=new B1();语法错误,要求局部内部类必须先定义后使用
class B1 { // 局部内部类,只能在所在的{}范围中使用,具备内部类的范围限定词和临
时变量一致,只能添加final或者abstract
public void ff() {
System.out.println(age);
A1.this.age = 555;// 可以直接访问外部类中的成员
System.out.println(birth);
// 语法报错,在局部内部类中使用外部的临时变量,则外部临时变量必须是
final的,只是final可以省略
// birth = new Date();针对引用类型修改地址是不允许,但是可以修改属性
System.out.println("B1...ff()");
}
}
B1 bb = new B1();
}
}
注意:局部内部类需要先定义后使用,不能是先使用后定义
匿名内部类
匿名内部类就是内部类的简写格式
public class A1{
public void pp(){
class B1 extends C1{}
}
}
//简化写法
public class A1{
public void pp(){
new C1(){};//原始命名类的写法class B1 extends C1{} new B1();
}
}
public class A1 {
public void pp(){
new Object(){
public void ff(){ //ff方法在父类中没有定义,则只能直接调用
System.out.println("anon inner class ... ff");
}
}.ff();
}
public static void main(String[] args) {
A1 a1=new A1();
a1.pp();
}
}

下面写法使用较多
public class A1 {
public void pp(){
Object obj=new Object(){
@Override//覆盖父类中定义的方法
public String toString() {
return ("anon inner class ... ff");
}
public void dd(){} //无法调用
};
System.out.println(obj.toString());//调用匿名内部类中覆盖定义的方法
}
}
匿名内部类的前提是必须继承或者实现一个外部类或者接口
new interfacename(){......};
new superclassname(){......};
如果父类中没有无参构造器,则()中应该有对应的参数
public class A1 {
public void pp(){
new B1(20){ //因为B1类中没有无参构造器,必须直接传入参数
};
}
}
class B1{
private int age;
public B1(int age){
this.age=age;
}
}

匿名内部类由于没有名字,所以它没有构造函数
如果这个匿名内部类继承了一个只含有带参数构造函数的父类,创建它的时候必须带上这些参数
不能定义静态成员
匿名内部类的使用场景
当方法参数是接口类型时,而且接口中的方法不超过三个 , 可以用匿名内部类作为实际参数进行传递
匿名内部类的使用限制
匿名内部类不能是抽象的
匿名内部类不能定义构造器,默认和父类相似的构造器
JDK1.8- 要求给局部内部类、匿名内部类访问的局部变量必须使用 final 修饰,从 JDK1.8 开始这个现
实被取消了,但是默认是 final 的(不能修改 )
public void pp() {
final Date birth = new Date();
class C1 {
public void ff() {
System.out.println(birth);
birth.setYear(2000);// 3900
// birth=new Date(); 语法报错
System.out.println("modify year:" + birth);
}
}
new C1().ff();
}
int 8 种简单类型 /Integer8 种简单类型的包装类 /String 的使用中应该注意
内部类的使用场景和好处
每个内部类都能独立的继承一个接口的实现,所以无论外部类是否已经继承了某个 ( 接口的 ) 实现,
对于内部类都没有影响。内部类使得多继承的解决方案变得完整
方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏
public class 牛{ private class 牛腿{} }
public class 牛{
private class 牛腿{}
}
方便编写事件驱动程序
btn.addActionListener(new ActionListener() { //添加按钮对应的事件处理
public void actionPerformed(ActionEvent e) {
showNewWindow(mainWin);
}
});
方便编写线程代码。
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值