Java进阶

1、类的继承

1.1继承:

继承是面向对象的三大特征之一,可以使得子类具有父类的属性和方法,还可以在子类中重新定义,追加属性和方法。

继承是指在原有类的基础上,进行功能扩展,创建新的类型。

(1)继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
(2)JAVA中类只有单继承,没有多继承!
(3)继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。
(3)继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示。
(4)子类和父类之间,从意义上讲应该具有"is a"的关系。
(5)extends的意思是“扩展”,子类是父类的扩展。

1.2 继承的使用

在java程序中,如果想声明一个类继承另一个类,需要使用extends关键字:
/*
* 定义Persion类
*/
class Persion{
// 定义name属性
String name;
// 定义Persion类的work方法
public void work() {
System.out.println("尽心尽力地工作");
}
}
/*
* 定义测试类
*/
public class Demo1 {
public static void main(String[] args) {
Student student = new Student();
student.name = "小明"; // 为该学生类的name属性进行赋值
student.printName(); // 调用该学生类的printName()方法
student.work(); // 调用Persion类继承来的work()方法
}
}

继承的 注意事项:

(1)在Java中,类只支持单继承,也就是说一个类只能有一个直接父类。

例如:下面这种情况是不合法的。

class A{}
class B{}



class C extends A,B { } // C类不可以同时继承A类和B类
(2) 多个类可以继承一个父类 ,例如下面这种情况是允许的。
class A{}


class B extends A{}

class C extends A{} // 类B和类C都可以继承类A

(3)在Java中,多层继承是可以的,即一个类的父类可以再去继承另外的父类。

例如C类继承自B类,而B类又可以去继承A类,这时,C类也可称作A类的 子类。下面这种情况是允许的。

class A{}


class B extends A{} // 类B继承类A,类B是类A的子类

class C extends B{} // 类C继承类B,类C是类B的子类,同时也是类A的子类

(4)在Java中,子类和父类是一种相对概念,也就是说一个类是某个类的父 类的同时,也可以是另一个类的子类。

B类是A类的子类,同时又是C类的父类。

class A{}


class B extends A{} // 类B继承类A,类B是类A的子类
class C extends B{} // 类C继承类B,类C是类B的子类,同时也是类A的
子类

继承的格式:

  • 格式: public class 子类名 extends 父类名{}
  • 例如: public class Zi extends Fu {}
  • Fu:是父类,也被称为基类、超类
  • Zi: 是子类,也被称为派生类

继承中子类的特点:     子类可以有父类的内容,子类还可以有自己特有的内容。

例如:创建一个父类Person


// 父类
public class Person {
    //public 公共的
    public int money = 1_0000_0000;
    public void say(){
        System.out.println("说话");
    }
 
}

创建一个子类Student

//student is person
//Teacher student也叫派生类或者子类
//子类可以继承父类的所有方法
public class Student extends Person{
 
}

创建一个测试Application类


public class Application {
    public static void main(String[] args) {
        Student student = new Student();
        student.say();
        System.out.println(student.money);
    }
}

结果:

说话
100000000
继承好处:

实现了数据和方法的共享
提高了代码的复用性(多个类相同的成员可以放到同一个类中)
提高了代码的维护性(如果方法的代码需要修改,修改一处即可)
提高了代码的可扩展性


继承弊端:

继承让类与类之间产生了关系,类的耦合性增强了,当父类发生变化时子类实现也不得不跟看变化,削弱了子类的独立性

1.3课堂任务

分别声明类:Animal,Cat、Dog
  确定三个类直接的关系:extends
  确定下列行为的归属,用方法表示在对应类中
(1)行走(walk)
(2)吃东西(eat)
(3)捉老鼠(work)
(4)看大门(work)
  确定下列特征的归属,用属性表示在对应类中
  1. 颜色(color)
  2. 名字(name)
  3. 年龄(age)
class Animal{
String color;
String name;
int age;
public void walk(){
System.out.println("走路!");
}
public void eat(){
System.out.println("吃饭!");
}
public void work(){
System.out.println("工作!");
}
}


class Cat{
String color;
String name;
int age;
public void walk(){
System.out.println("走路!");
}
public void eat(){
System.out.println("吃饭!");
}
public void work(){
System.out.println("捉老鼠!");
}
}


class Dog{
String color;
String name;
int age;
public void walk(){
System.out.println("走路!");
}
public void eat(){
System.out.println("吃饭!");
}
public void work(){
System.out.println("看大门!");
}
}
因为 Cat Dog 是有重复的属性、方法,因此可以将这些重复的数据抽离 出来,放在一同统一的类中,这个被抽出来存放统一属性和方法的类,我 们就可以作为 父类 ,被抽了数据的类,作为其 子类 ,使用 extends 关键字 将其关联起来。
class Animal{
  String color;
  String name;
  int age;

public void walk(){
System.out.println("走路!")
}

public void eat(){
System.out.println("吃饭!")
}

public void work(){
System.out.println("工作!")
}


}

1.4 super

super 关键字的用法和 this 关键字的用法相似

  • this:代表本类对象的引用(this关键字指向调用该方法的对象一般我们是在当前类中使用this关键字所以我们常说this代表本类对象的引用)
  • super:代表父类存储空间的标识(可以理解为父类对象引用)
    关键字访问成员变量访问构造方法访问成员方法
    thisthis.成员变量
    访问本类成员变量
    this(...)
    访问本类构造方法
    this.成员方法(...)
    访问本类成员方法
    supersuper.成员变量
    访问父类成员变量
    super(...)
    访问父类构造方法
    super,成员方法(...)
    访问父类成员方法

1.5子父类中构造方法的特点

如果子类中出现了父类同名的成员变量,这时子类中若要访问父类中的成员变量,必须使用关键字 super来完成。super用来表示当前对象中包含的父类对象空间的引用:

class Father
{
//Father中的成员变量。
int num = 5;
}
class Son extends Father
{
//Son中的成员变量
int num = 6;
public void show(){
//子父类中出现了同名的成员变量时
//在子类中需要访问父类中非私有成员变量时,需要使用super关键字
//访问父类中的num
System.out.println("Father num="+super.num);
//访问子类中的num2
System.out.println("Son num2="+this.num);
}
}
当在程序中通过对象调用方法时, 会先在 子类 中查找有没有对应的方法 ,若子类中存在就会执行子类中的 方法,若子类中不存在就会执行父类中相应的方法。
class Persion3{
String name; // 定义name属性
// 定义Persion类的work方法
public void work() {
System.out.println("尽心尽力地工作");
}
public void display(){
System.out.println("这是一个Persion类");
}
}
/*
* 定义学生类Student 继承 Persion类
*/
class Student3 extends Persion3 {
// 定义一个打印name的方法
public void display(){
System.out.println("这是一个Student类");
}
}
public class Demo3 {
public static void main(String[] args) {
Student3 student3=new Student3();
student3.display();
student3.work();
}
}
在创建子类对象时, 因为子类 继承 父类的 成员变量 成员方法 ,所以 子类会先加载父类 ,调用 父类的构造 方法 。因此 子类 所有构造方法 第一行 默认的隐式super()语句来调用父类的构造方法 。如果当父类 没有空参数构造方法 时,子类的 构造方法必须有显示的super语句 指定要访问父类有参数的构造方法
class Persion5{
String name; // 定义name属性
int age;
public Persion5(String name, int age){
this.name=name;
this.age=age;
}
}
/*
* 定义学生类Student 继承 Persion类
*/
class Student5 extends Persion5 {
// 定义一个打印name的方法
public Student5(String name,int age){
super(name,age);
}
public void printInfo(){
System.out.println("name="+name+",age="+age);
}
}
public class Demo5 {
public static void main(String[] args) {
Student5 student5=new Student5("张三",20);
student5.printInfo();
}
}

2、抽象类

2.1概念

在一个类中, 含有的方法只有方法名 没有方法体的类 ,我们称之为 抽象类。

2.2抽象方法定义的格式:

public abstract 返回值类型 方法名(参数);

2.3抽象类定义的格式:

public abstract class 类名 {

语句

}
 
public abstract class Teacher{
//抽象函数。需要abstract修饰,分号;结束
public abstract void work();
}

在Java中,我们通过在类前添加关键字abstract(抽象的)来定义抽象类。如下图所示 : 
public abstract class Animal {
    //Animal类此时就是一个抽象类。
}
 
class Dog extends Animal {
    //Dog类继承了Animal类,是Animal类的子类。
}

2.4应用

 当父类需要定义一个方法,却不能明确该方法的具体实现细节时,可以将该方法定义为abstract,具体实现细节延迟到子类。(让子类重写这个方法)
                就比如我们刚才说的——Animal类中的eat() 方法,我们可以先将其定义为抽象类,然后在子类中,比如说Dog类中重写eat() 方法,给出对Dog类对象“吃”这一行为的一些具体描述。
                up以Animal类,Dog类和Test类为例,代码如下 : 

package knowledge.polymorphism.about_abstract.introduction;
 
public abstract class Animal {   /** 父类 */
    //将Animal类中的eat() 方法定义为抽象类,具体实现延迟到子类。
    public abstract void eat();
}
 
class Dog extends Animal {      /** 子类 */
    //子类重写父类的抽象方法,也称为子类实现了该抽象方法。
    public void eat() {
        System.out.println("狗是杂食性动物,喜食肉类,喂养时应该以动物蛋白为主,素食为辅。");
    }
}
 
class Test {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();
    }
}

2.5抽象类的好处

该案例中猫和狗都有名字这个属性,也都有叫这个行为,所以我们可以将共性的内容抽取成一个父类,Animal类,但是由于猫和狗叫的声音不一样,于是我们在Animal类中将叫的行为写成抽象的。代码如下:

public abstract class Animal {
    private String name;
​
    //动物叫的行为:不具体,是抽象的
    public abstract void cry();
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
}

接着写一个Animal的子类,Dog类。代码如下:

public class Dog extends Animal{
    public void cry(){
        System.out.println(getName() + "汪汪汪的叫~~");
    }
}

然后,再写一个Animal的子类,Cat类。代码如下

public class Cat extends Animal{
    public void cry(){
        System.out.println(getName() + "喵喵喵的叫~~");
    }
}

最后,再写一个测试类,Test类。

public class Test2 {
    public static void main(String[] args) {
        // 目标:掌握抽象类的使用场景和好处.
        Animal a = new Dog();
        a.cry();    //这时执行的是Dog类的cry方法
    }
}

假设现在代码有需要加一个Pig类,也有叫的行为,这时候也很容易原有功能扩展。只需要让Pig类继承Animal,复写cry方法就行。

public class Pig extends Animal{
    @Override
    public void cry() {
        System.out.println(getName() + "嚯嚯嚯~~~");
    }
}

此时,创建对象时,让Animal接收Pig,就可以执行Pig的cry方法

public class Test2 {
    public static void main(String[] args) {
        // 目标:掌握抽象类的使用场景和好处.
        Animal a = new Pig();
        a.cry();    //这时执行的是Pig类的cry方法
    }
}

2.6 抽象类特点总结

  1. 抽象类由关键字abstract来修饰;
  2. 抽象方法也有关键字abstract来修饰,且没有方法体连大括号都没有
  3. 抽象类可以含有抽象方法,也可以含有普通方法,也可以任何方法都不含
  4. 抽象类不能直接创建对象(建自己的对象),因为抽象类中含有了抽象方法 后,使用对象的引用去调用是没有任何意义的;
  5. 抽象类是可以通过多态的形式,建立子类对象的,这种方式叫做:向上造型
  6. 抽象类也是类,类与类之间就可以形成继承关系当一个普通类继承了抽象 类后,就需要实现抽象类的全部抽象方法,即重写;否则,当前的普通类业 的是一个抽象,只继承不线上是被允许的;

3、接口

3.1 接口概念

官方解释:Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。

    我的解释:接口可以理解为一种特殊的类,里面全部是由全局常量和公共的抽象方法所组成。接口是解决Java无法使用多继承的一种手段,但是接口在实际中更多的作用是制定标准的。或者我们可以直接把接口理解为100%的抽象类,既接口中的方法必须全部是抽象方法。(JDK1.8之前可以这样理解)

3.2接口的特点

 就像一个类一样,一个接口也能够拥有方法和属性,但是在接口中声明的方法默认是抽象的。(即只有方法标识符,而没有方法体)。

(1)接口指明了一个类必须要做什么和不能做什么,相当于类的蓝图。
(2)一个接口就是描述一种能力,比如“运动员”也可以作为一个接口,并且任何实现“运动员”接口的类都必须有能力实现奔跑这个动作(或者implement move()方法),所以接口的作用就是告诉类,你要实现我这种接口代表的功能,你就必须实现某些方法,我才能承认你确实拥有该接口代表的某种能力。
(3)如果一个类实现了一个接口中要求的所有的方法,然而没有提供方法体而仅仅只有方法标识,那么这个类一定是一个抽象类。(必须记住:抽象方法只能存在于抽象类或者接口中,但抽象类中却能存在非抽象方法,即有方法体的方法。接口是百分之百的抽象类)
(4)一个JAVA库中接口的例子是:Comparator 接口,这个接口代表了“能够进行比较”这种能力,任何类只要实现了这个Comparator接口的话,这个类也具备了“比较”这种能力,那么就可以用来进行排序操作了。

3.3接口的定义

(1)接口用关键字interface来定义:public interface 接口名 {}

public interface Inter {
public abstract void method1();
public abstract void method2();
}

(2)接口 不能实例化,且接口没有构造方法
(3)接口和类之间是 实现 关系,通过 implements 关键字表示
public class 类名 implements 接口名 {}
(4)接口的子类(实现类)
要么重写接口中的所有抽象方法
要么是抽象类
public Son implements Inter {
public void method1(){ }
public void method2(){ }
}


public abstract class Son implements Inter{
}

3.4接口的成员特点

(1)成员变量

只能是常量

默认修饰符: public static final

(2)构造方法

没有

(3)成员方法

只能是抽象方法
默认修饰符: public abstract
关于接口中的方法, JDK8 JDK9 中有一些新特性

3.5abstract关键字的冲突

(1)final
abstract 修饰的方法,强制要求子类重写,被 final 修饰的方法子类不能重写
(2)private
abstract 修饰的方法,强制要求子类重写,被 private 修饰的方法子类不能重写
(3)static
static 修饰的方法可以类名调用,类名调用抽象方法没有意义

4、类的高级特性

4.1static修饰符

static 关键字的介绍: static 静态 的意思,可以修饰成员变量,也可以修饰成员方法。
public class Student {
String name;
int age;
//采用static修饰成员变量,称之为静态变量
static String schoolName;
//采用static修饰成员方法,称之为静态方法
public static void showScoreInfo() {
System.out.println(schoolName + "的所有的学生学完40学分才能毕业!");
}
}
public class Demo1 {
public static void main(String[] args) {
//通过类名.成员变量访问静态变量
Student.schoolName="电子科技大学";
System.out.println(Student.schoolName);
//通过类名.方法名访问静态方法
Student.showScoreInfo();
}
}

static 修饰成员的特点

  • 被其修饰的成员, 被该类的所有对象所共享
  • 多了一种调用方式, 可以通过类名调用
  • 随着类的加载而加载, 优先于对象存在

static 成员变量

  • 共享列表

static 成员方法

  • 常用于工具类
重新认识 main 方法
public class HelloWorld {
public static void main(String[] args) {
System.out.println("HelloWorld");
}
}
  • publicJVM调用,访问权限足够大
  • staticJVM调用,不用创建对象        因为main方法是静态的,所以测试类中其他方法也需要是静态的
  • voidJVM调用,不需要给JVM返回值
  • main一个通用的名称,虽然不是关键字,但是被JVM识别
  • String[] args: 以前用于接收键盘录入数据的,现在没用

4.2final关键字

final 关键字的介绍
final 关键字意思是 最终,不可变的 ,可以修饰(方法,类,变量)
final 修饰的特点:
  • 修饰方法:表明该方法是最终方法,不能被重写
  • 修饰类:表明该类是最终类,不能被继承
  • 修饰变量:表明该变量是常量,不能再次被赋值
通常使用 public static final 修饰的变量来完成定义。此时 变量名用全部大写
多个单词使用下划线连接
  1. final修饰类不可以被继承,但是可以继承其他类,伪代码如下:
class Grandfather {
}
final class Father extends Grandfather {//可以继承Grandfather类
}
class Son extends Father{//不能继承Father类
}
2. final 修饰的方法不可以被覆盖 , 但父类中没有被 final 修饰方法,子类覆盖后 可以加 final 伪代码如下:
class Father {
// final修饰的方法,不可以被覆盖,但可以继承使用
public final void method1(){
}
public void method2(){
}
}
class Son extends Father {
//只能重写method2方法
public final void method2(){
}
}

3.final修饰的变量称为常量,这些变量只能赋值一次,伪代码如下:

final int num= 20;
num = 30; //赋值报错,final修饰的变量只能赋值一次

4.引用类型的变量值为对象地址值,地址值不能更改,但是地址内的对象属性值 可以修改,伪代码如下:

final Person p1 = new Person();
Person p2 = new Person();
p1 = p2; //final修饰的变量p,所记录的地址值不能改变
p1.name = "李四";//可以更改p对象中name属性值
p1.age= 24;//可以更改p对象中age属性值
p1 不能为别的对象,而 p1 对象中的 name age 属性值可更改。

5.修饰成员变量,需要在创建对象前赋值,否则报错。 没有显式赋值时,当有多个构造方法的均需要为其赋值,伪代码如下:

class Demo {
//直接赋值
final int num1= 100;
//final修饰的成员变量,需要在创建对象前赋值,否则报错。
final int num2;
public Demo(){
//可以在创建对象时所调用的构造方法中,为变量num2赋值
Num2 = 2016;
}
}

6.在java程序开发中,我们想在类中定义一个静态常量, 通常使用public static final修饰的变量来完成定义。此时变量名用全部大写, 多个单词使用下划线连接,伪代码如下:

class Company {
public static final String Type_COMPANY = "初创型";
}

7.需要注意的是: 接口中的每个成员变量都默认使用 public static final 修饰。 所有接口中的成员变量已是静态常量,由于接口没有构造方法,所以必须显示赋值。 可以直接用接口名访问。

interface Inter {
public static final int COUNT = 100;
public static final String USERNAME= “张三”;
public static final int PASSWORD= 123456;
}

4.3代码块

概念:

代码块又叫初始化块,是类的一部分,类似于方法,将逻辑语句封装在方法体中,通过{}包围起来。但代码块又和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是在加载类时,或者创建对象时隐式调用。

定义:在 Java 类下,使用 { } 括起来的代码被称为代码块。
分类:
  1. 局部代码块
  2. 构造代码块
  3. 静态代码块
  4. 同步代码块
局部代码块
位置:方法中定义
作用:限定变量的生命周期,及早释放,提高内存利用率
构造代码块
位置:类中方法外定义
特点:每次构造方法执行的时,都会执行该代码块中的代码,并且在构造方法执行前执行
作用:将多个构造方法中相同的代码,抽取到构造代码块中,提高代码的复用性
静态代码块
位置:类中方法外定义
特点:需要通过static关键字修饰,随着类的加载而加载,并且只执行一次
作用:在类加载的时候做一些数据初始化的操作
(1)static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着 类的加载而执行,并且只会执行一次。如果是普通代码块,每创建一个对象,就执行一次。
public class CodeBlockDetail{
    psvm{
        AA aa1 = new AA();
        AA aa2 = new AA();
    }
}
class AA{
    //静态代码块,在类加载的时候执行,并且只会执行一次
    static{
        sout("AA的静态代码块1被执行......")
    }
}

(2)普通的代码块,在创建对象实例时,会被隐式的调用。被创建一次,就会调用一次。如果只是使用类的静态成员时,普通代码块并不会被执行。

public class CodeBlockDetail{
    psvm{
        AA aa1 = new AA();
        AA aa2 = new AA();
    }
}
class AA{
    //静态代码块,在类加载的时候执行,并且只会执行一次。普通代码块每实例化一个对象,就执行一次
    static{
        sout("AA的静态代码块1被执行......")
    }
    {
        sout("AA的普通代码块......")
 
    }
}

4.4匿名对象

  概念:匿名对象是指创建对象时, 只有创建对象的语句,却没有把对象地址值赋值给某个变量
  匿名对象的使用,有如下几种方式:
创建匿名对象直接使用,没有变量名,只能使用一次。
    new Person().eat() //eat方法被一个没有名字的Person对象调用了
    匿名对象可以作为 方法接收的参数 方法返回值 使用
案例如下:
class Person2 {
private String name;
private int age;
}
class Tools {
public static Person2 getPerson(){
//匿名对象作为方法返回值
return new Person2();
}
public static void method(Person2 p){}
}
class Demo4 {
public static void main(String[] args) {
//调用getPerson方法,得到一个Person对象
Person2 person =Tools.getPerson();
//调用method方法
Tools.method(person);
//匿名对象作为方法接收的参数
Tools.method(new Person2());
}
}

5、内部类

内部类是类中的五大成分之一(成员变量、方法、构造器、内部类、代码块),如果一个类定义在另一个类的内部,这个类就是内部类。

当一个类的内部,包含一个完整的事物,且这个事物没有必要单独设计时,就可以把这个事物设计成内部类

public class Car{
    //内部类
    public class Engine{
        
    }
}

(1)成员内部类:(在类的内部方法的外部编写的类就是成员内部类)

成员内部类特点:

1.成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员);

2.同名的属性名/方法名访问外部类时 → 外部类.this.成员名

成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。所以在外部类访问内部类的时候必须先实例化外部类对象

Outer outer= new outer();
		Inner inner = outer.new Inner();
        //或者如下一句代码:
        Outer.Inner inner = new Outer().new Inner();

注意:

1.成员内部类可以使用四种权限修饰符进行修饰(四种权限修饰符:public(公有的) >protected(受保护的) > (default)(缺省/默认的) > private(私有的));
2.成员内部类中不能书写静态变量和方法。

案例演示:

public class Outer {
    String name = "外部类的类名";
    static String type = "外部类的type属性";
    private int item = 1;
 
    public static void show() {
        System.out.println("掉用外部类中的show方法");
    }
    public void print() {
        System.out.println("调用外部类中的打印方法");
    }
 
    //成员内部类 可以使用权限修饰符进行修饰
    public class Inner{
        //static double weight = 1.8;  //成员内部类中不能使用static修饰变量和方法
        String name = "内部类的类名";
 
        public void innerShow(){
            //成员内部类可以直接访问外部类的属性和方法
            show();
            print();
            System.out.println(type);
            System.out.println(item);
            System.out.println("我是:" + name);
            //进行特指访问时 使用类名.this.变量名进行访问
            System.out.println("我是:" + Outer.this.name);
 
        }
    }
 
    public static void main(String[] args) {
        //成员内部类对象的创建步骤
        //1.第一步需要实例化外部类对象
        //2.第二步正常实例化内部类对象 但是new关键字要改成 外部类对象名.new
           /*Outer outer = new Outer();
            Inner inner = outer.new Inner();*/
        //或者这样创建
        Outer.Inner inner = new Outer().new Inner();
        inner.innerShow();
    }
}

(2)匿名内部类(注意:匿名内部类只是没有类名,其他的都是具备的)

匿名内部类特点

匿名内部类不能定义任何静态成员、方法和类,只能创建匿名内部类的一个实例。一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。

匿名内部类的格式:

new 父类/接口(参数值){
    @Override
    重写父类/接口的方法;
}

案例:

// 实现关系下的匿名内部类:
interface Dao {
	void show();
}
 
public class AnonymousDemo {
    //编写回调方法 :callInner
    public void callInner(){
        // 接口关系下的匿名内部类
        new Dao(){
            //实现子类 但是没有名字 所以叫匿名内部类
            @Override
            public void show() {
                System.out.println("接口方法...");
            }
        }.show();
    }
}
// 测试:
public class Demo {
    public static void main(String[] args) {
        AnonymousDemo anonymousDemo = new AnonymousDemo();
        anonymousDemo.callInner();
    }
}

匿名内部类可用于给方法传递实参,演示如下:

interface Dao {
	void show();
}
 
public class AnonymousDemo {
    //编写回调方法:callInner 参数类型为接口Dao
    private static void callInner(Dao d) {
        d.show();
    }
 
    public static void main(String[] args) {
        callInner(new Dao() {//接口回调
 
            //实现子类 但是没有名字 所以叫匿名内部类
            @Override
            public void show() {
                System.out.println("匿名内部类用于给方法传递实参");
            }
        });
    }
    
}

说明:首先有一个接口,然后在使用的类中编写了一个方法(参数类型是接口对象),并使用接口中未实现的方法。
我们调用此方法直接构造一个接口对象传入,此时会自动生成一个此接口的子类(匿名内部类)实现接口中的方法。本质传入的类便是此时的匿名内部类。

(3)静态内部类(在类中编写的以static修饰的类称为静态内部类)

静态内部类特点
1.静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static;
2.静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法;
3.静态内部类中即能声明静态成员也可以声明非静态成员。

静态内部类创建对象时,需要使用外部类的类名调用。

//格式:外部类.内部类 变量名 = new 外部类.内部类();
Outer.Inner in = new Outer.Inner();
in.test();


详见案例演示:


public class Static {
    static String name = "外部类的类名";
    //静态内部类中不能访问外部类非静态成员
    String type = "外部类的type属性";
 
    public static class Inner{
        //四种权限修饰符可以修饰静态内部类
        public String name = "静态内部类的类名";
        static double weight = 1.8;
        String type = "静态内部类的type属性";
        public void show(){
            System.out.println("我是:" + weight);
            System.out.println("我是:" + type);
            System.out.println("我是:" + name);
            //System.out.println("我是:" + Static.type);//静态内部类中不能访问外部类非静态成员
            System.out.println("我是:" + Static.name);
        }
    }
 
    public static void main(String[] args) {
        //静态内部类可以直接实例化 不需要依附于外部类
        Inner inner = new Inner();
        inner.show();
    }
}

输出结果:

我是:1.8
我是:静态内部类的tepy属性
我是:静态内部类类名
我是:外部类的类名

(4)局部内部类 (编写在方法的内部的类称之为局部内部类,也可以称为方法内部类)

局部内部类的特点
1.局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内;
2.局部内部类不可使用权限修饰符 静态(static)修饰符进行修饰 同局部变量相同;
3.局部内部类可以直接访问方法中的属性;
4.局部内部类 可以直接访问方法外部类中属性和方法;
5.局部内部类 创建对象 要在方法内部 局部内部类的外部声明。

局部内部类是定义在方法中的类,和局部变量一样,只能在方法中有效。

public class Outer{
    public void test(){
        //局部内部类
        class Inner{
            public void show(){
                System.out.println("Inner...show");
            }
        }
        
        //局部内部类只能在方法中创建对象,并使用
        Inner in = new Inner();
        in.show();
    }
}

详见案例演示:

public class Partial {
    String name = "外部类的类名";
    String type = "外部类的type属性";
    private int item = 1;
 
    public static void show() {
        System.out.println("掉用外部类中的show方法");
    }
    public void print() {
        System.out.println("调用外部类中的打印方法");
    }
 
    public void demo(){
        String name = "外部类方法deme()内部的方法名";
        String type = "外部类方法deme()内部的type属性";
        /*编写在方法的内部的类称之为局部内部类
        局部内部类不可使用权限修饰符 静态修饰符进行修饰 同局部变量相同
        局部内部类与局部变量使用范围一样 在此方法内部
        局部内部类可以直接访问方法中的属性 重名时使用参数传递完成访问*/
        class Inner{
            //局部内部类 可以访问方法外部类中属性和方法
            String name = "局部类的类名";
            public void showInner(String name){
                show();
                print();
                System.out.println("我是:"+ type);
                System.out.println("我是:"+ Partial.this.type);
                System.out.println(item);
                System.out.println("我是:" + this.name);
                System.out.println("我是:" + name);
                System.out.println("我是:" + Partial.this.name);
            }
        }
        //局部内部类 创建对象 要在方法内部 局部内部类的外部声明
        Inner inner = new Inner();
        inner.showInner(name);
    }
 
    public static void main(String[] args) {
        Partial partial = new Partial();
        partial.demo();
    }
}

输出结果:

掉用外部类中的show方法
调用外部类中的打印方法
我是:外部类方法deme()内部的type属性
我是:外部类的type属性
1
我是:局部类的类名
我是:外部类方法deme()内部的方法名
我是:外部类的类名

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值