java内部类相关的学习笔记

Java static变量、成员变量、构造函数 三者的初始化顺序:

Java代码中父类和子类中,static变量 – 成员变量 – 构造函数 三者的调用先后顺序:

先初始化父类Static --> 再初始化子类的Static --> 再初始化父类的其他成员变量->父类构造方法->子类其他成员变量->子类的构造方法。

系统默认值的给予比通过等号的赋予先执行。

一个类中的static变量或成员变量的初始化顺序,是按照声明的顺序初始化的。

举个栗子:

public class Main {
     
    public static void main(String[] args) {
        B b = new B();
    }
     
    public static class A {
        public static MyClass1 myClass1 = new MyClass1();
        private MyClass2 myClass2 = new MyClass2();
         
        A(){
            System.out.println("A的构造函数");
        }
    }
     
    public static class B extends A {
        public static MyClass3 myClass3 = new MyClass3();
        private MyClass4 myClass4 = new MyClass4();
         
        B(){
            System.out.println("B的构造函数");
        }
    }
     
    public static class MyClass1 {
        MyClass1(){
            System.out.println("MyClass1的构造函数");
        }
    }
     
    public static class MyClass2 {
        MyClass2(){
            System.out.println("MyClass2的构造函数");
        }
    }
     
    public static class MyClass3 {
        MyClass3(){
            System.out.println("MyClass3的构造函数");
        }
    }
     
    public static class MyClass4 {
        MyClass4(){
            System.out.println("MyClass4的构造函数");
        }
    }
     
}

代码运行的结果是:

MyClass1的构造函数
    MyClass3的构造函数
    MyClass2的构造函数
    A的构造函数
    MyClass4的构造函数
    B的构造函数

Java内部类:

1.为什么要要使用内部类?

为什么要使用内部类?在《Think in java》中有这样一句话:使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。

在我们程序设计中有时候会存在一些使用接口很难解决的问题,这个时候我们可以利用内部类提供的、可以继承多个具体的或者抽象的类的能力来解决这些程序设计问题。可以这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。

其实使用内部类最大的优点就在于它能够非常好的解决多重继承的问题,但是如果我们不需要解决多重继承问题,那么我们自然可以使用其他的编码方式,但是使用内部类还能够为我们带来如下特性(摘自《Think in java》):

**1、**内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。

**2、**在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。

**3、**创建内部类对象的时刻并不依赖于外围类对象的创建。

**4、**内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。

**5、**内部类提供了更好的封装,除了该外围类,其他类都不能访问。

到这里了我们需要明确一点,内部类是个编译时的概念,一旦编译成功后,它就与外围类属于两个完全不同的类(当然他们之间还是有联系的)。对于一个名为OuterClass的外围类和一个名为InnerClass的内部类,在编译成功后,会出现这样两个class文件:OuterClass.class和OuterClass$InnerClass.class。

在Java中内部类主要分为:成员内部类局部内部类匿名内部类静态内部类

1.成员内部类

成员内部类也是最普通的内部类,它是外围类的一个成员,所以他是可以无限制的访问外围类的所有 成员属性和方法,尽管是private的,但是外围类要访问内部类的成员属性和方法则需要通过内部类实例来访问。

在成员内部类中要注意两点,**第一:**成员内部类中不能存在任何static的变量和方法;**第二:**成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类。

public class OuterClass {
    private String str;
    
    public void outerDisplay(){
        System.out.println("outerClass...");
    }
    
    public class InnerClass{
        public void innerDisplay(){
            //使用外围内的属性
            str = "chenssy...";
            System.out.println(str);
            //使用外围内的方法
            outerDisplay();
        }
    }
    
    /*推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 */
    public InnerClass getInnerClass(){
        return new InnerClass();
    }
    
    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        OuterClass.InnerClass inner = outer.getInnerClass();
        inner.innerDisplay();
    }
}
--------------------
chenssy...
outerClass...
2.局部内部类

(一般不怎么用,掌握就好)

有这样一种内部类,它是嵌套在方法和作用于内的,对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类,局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法和属性中被使用,出了该方法和属性就会失效。

3.匿名内部类

为什么会有匿名内部类?

说白了,就是因为想偷懒,不想写太多代码。如果可以,程序员完全可以通过实现接口或者继承抽象类的方式来实现而不用创建匿名内部类。但是使用匿名内部类的优点是显而易见的,可以少些代码,而且代码更加简洁。

一般情况下要使用接口和抽象类,大家都是去设计一个类实现接口,继承抽象类。然后实例化类的对象,执行对象的方法。而匿名内部类,一般是在对接口或抽象类的实现类使用不是很广泛,很通用,只在当前的场景用一下时,就可以这么去使用匿名内部类,而不需要专门去创建实现类了。

匿名内部类的定义

先看匿名内部类的定义的语法格式:

第一种:

new 实现接口()
{
    //匿名内部类类体部分
}

第二种:

new 父类构造器(实参列表)
{
  //匿名内部类类体部分
}

如何使用匿名内部类(用第一种实现接口的格式):

interfance Product
{
  public double getPrice();
  public String  getName();
}

上面代码定义一个接口,接口里面两个抽象方法

public class Anonymous
{
  public void test (Product p)
  {
      System.out.println(p.getName()+"--------"+p.getPrice());
  }
  public static void main(String [ ] args )
    {
        Anonymous as= new Anonymous ();
          as.test(new Product( )//此处实现接口并实现抽象方法
            {
               public double getPrice( )//实现方法
                 {
                    return 8888;
                  }
                 public String getName( )//实现方法
                  {
                     return "I can do it ";
                  }

            });
    }
}

上面代码很简单,就是定义了一个类Anonymous,在类里定义了一个test方法。然后就是创建Anonymous对象,调用他的实例方法test()。 不过调用test()方法时,要传入一个Product对象。但是由于Product是一个接口,无法创建对象,所以要实现该接口。因此此处采用匿名内部类的方式进行,并实现接口中全部的抽象方法。

匿名内部类的一些特点

匿名内部类没有类名匿名内部类中不能声明静态变量(匿名内部类内部访问静态非静态都可以访问,外部访问没有类名无法访问)(可以声明常量)。匿名内部类总不能声明静态方法不能定义构造方法(本身在定义匿名内部类的同时已经实例化对象,这个类也不能再实例化另外的对象。没有类名也没有办法编写构造方法)

4.静态内部类/嵌套内部类

关键字static中提到Static可以修饰成员变量、方法、代码块,其他它还可以修饰内部类,使用static修饰的内部类我们称之为静态内部类,不过我们更喜欢称之为嵌套内部类。静态内部类与非静态内部类之间存在一个最大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围内,但是静态内部类却没有。没有这个引用就意味着:

1.它的创建是不需要依赖于外围类的。

2.它不能使用任何外围类的非static成员变量和方法

Java中可实现多继承的三种方法

在java中,原则上是不允许多继承的,也就是类与类之间只可以单继承。
那么,有没有办法,可以在不使用接口的情况下实现多继承呢? 答案是可以。

有下面三种方法:

1.多层继承

但多层继承一般建议不超过三次,且代码较冗余

2.内部类

3.接口

接口、抽象类的区别:

抽象类:

对于面向对象编程来说,抽象是它的一大特征之一。在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类。这两者有太多相似的地方,又有太多不同的地方。很多人在初学的时候会以为它们可以随意互换使用,但是实际则不然。

抽象方法定义:抽象方法是一种特殊的方法,它只有声明,而没有具体的实现,抽象方法的声明格式为:

abstract void fun();

抽象类定义:包含抽象方法的类叫做抽象类。

包含抽象方法的类称为抽象类,但并不意味着抽象类中只能有抽象方法,它和普通类一样,同样可以拥有成员变量和普通的成员方法。注意,抽象类和普通类的主要有三点区别:

**1.**抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。😁

**2.**抽象类不能用来创建对象;😁

**3.**如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。😁

在其他方面,抽象类和普通的类并没有区别。

接口:

接口中可以含有 变量和方法。但是要注意,接口中的变量会被隐式地指定为public static final变量(并且只能是public static final变量,用private修饰会报编译错误),而方法会被隐式地指定为public abstract方法且只能是public abstract方法(用其他关键字,比如private、protected、static、 final等修饰会报编译错误),并且接口中所有的方法不能有具体的实现,也就是说,接口中的方法必须都是抽象方法。从这里可以隐约看出接口和抽象类的区别,!!!!!!种极度抽象的类型,它比抽象类更加“抽象”,并且一般情况下不在接口中定义变量

**我的理解:**public static final:其中public是规定的变量访问权限;static 规定了变量创建的条件,不依赖于它的父级;final规定了变量的值是不能被更改的。所以这样的变量特性是:一个公共的,不依赖父级就能初始化且不能被修改其值的变量。

抽象类和接口的区别:

1.语法层面上的区别

1)抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;

2)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;

3)接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;

4)!!!一个类只能继承一个抽象类,而一个类却可以实现多个接口。(这里就说明了java不能实现继承多个类的特性,但可以通过实现多个接口代替多继承)

下面看一个网上流传最广泛的栗子:门和警报的例子:门都有open( )和close( )两个动作,此时我们可以定义通过抽象类和接口来定义这个抽象概念:

abstract class Door {
    public abstract void open();
    public abstract void close();
}

或者:

interface Door {
    public abstract void open();
    public abstract void close();
}

但是现在如果我们需要门具有报警alarm( )的功能,那么该如何实现?下面提供两种思路:

1)将这三个功能都放在抽象类里面,但是这样一来所有继承于这个抽象类的子类都具备了报警功能,但是有的门并不一定具备报警功能;

2)将这三个功能都放在接口里面,需要用到报警功能的类就需要实现这个接口中的open( )和close( ),也许这个类根本就不具备open( )和close( )这两个功能,比如火灾报警器。

从这里可以看出, Door的open() 、close()和alarm()根本就属于两个不同范畴内的行为,open()和close()属于门本身固有的行为特性,而alarm()属于延伸的附加行为。因此最好的解决办法是单独将报警设计为一个接口,包含alarm()行为,Door设计为单独的一个抽象类,包含open和close两种行为。再设计一个报警门继承Door类和实现Alarm接口。

interface Alram {
    void alarm();
}
 
abstract class Door {
    void open();
    void close();
}
 
class AlarmDoor extends Door implements Alarm {
    void oepn() {
      //....
    }
    void close() {
      //....
    }
    void alarm() {
      //....
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值