7.面向对象

1.1面向对象概述

“面向对象”(英语:Object Oriented,简称OO)是一种以事物为中心的编程思想。

面向对象程序设计(英语:Object-oriented programming,缩写:OOP),是一种程序开发的方法。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。

对象:在现实生活中存在的具体的一个事物。

类:对某种类型事物的共性属性与行为的抽取。

属性:对象具有的各种特性,每个对象的每个属性都拥有特定的值。

行为:对象能够执行的操作。

类和对象的关系:类是对象的抽象,对象是类的实体。

面向对象特征:继承,封装,多态。

开发的过程其实就是不断的创建对象,然后使用对象,指挥对象做事情。

1.2类的创建

类的重要性:类是Java程序的基本组成单位。

类是什么:类是对现实生活中一类具有共同属性和行为的事物的抽象,确定对象将会拥有的属性和行为。

类的组成:属性和行为

属性:在类中通过成员变量来体现(类中方法外的变量)

行为:在类中通过成员方法来体现(和前面的方法相比去掉static关键字即可)

package com.boxiaoyuan.www;

public class Car {
    private String name = null;
    public Car(String name) {
        this.name = name;
    }
    public void run() {
        System.out.println(this.name + "车在跑");
    }
}

package com.boxiaoyuan.www;

public class CarDemo {
    public static void main(String[] args) {
        Car car = new Car("宝马");
        car.run();
    }
}

成员变量:  定义在类中的变量,在整个类内部有效,属于对象,随着对象的创建而创建,随着对象的消失而消失,存储在堆内,当没有引用指向其时,才进行垃圾回收,如果没有默认值,自动给它赋初始值。

局部变量:  定义在方法中的变量,使用完马上释放空间,存储在栈内存中,当不再使用时,马上会释放,如果想要使用必须手动初始化。

初始值:

成员变量存储在堆中,如果没有赋初值,它有默认值。

  1. 整数byte、short、int、long =0;
  2. char='u0000';
  3. boolean =false;
  4. String =null;
  5. 类类型 =null;
  6. 数组 =null;

局部变量:(没有默认的初始值)如果要想使用必须手动初始化。

1.3封装

1.3.1不使用封装

package com.boxiaoyuan.test;

public class Demo0028 {     
    public static void main(String[] args) {
        Employee boxiaoyuan = new Employee();
        boxiaoyuan.name = "boxiaoyuan";
        boxiaoyuan.id = "111111";
        boxiaoyuan.gender = "不是男人";//传入了非法的参数
        boxiaoyuan.work();
    }
}
class Employee{
    String name;
    String id;
    String gender;
    
    public void work() {
        System.out.println(id+":"+name+":"+gender+"在工作");
    }
    
}

总结:不使用封装,很容易赋值错误,并且任何人都可以更改,造成信息不安全。

1.3.2使用封装

设置类的属性为private,这样就不能使用对象名.属性名的方式直接访问对象的属性。

public class Demo0028 {     
    public static void main(String[] args) {
        Employee boxiaoyuan = new Employee();
        boxiaoyuan.name = "boxiaoyuan";//编译报错
        boxiaoyuan.id = "111111";//编译报错
        boxiaoyuan.gender = "不是男人";//传入了非法的参数,编译报错
        boxiaoyuan.work();
    }
}
class Employee{
    private String name;
    private String id;
    private String gender;
    
    public void work() {
        System.out.println(id+":"+name+":"+gender+"在工作");
    }
}

说明:

   1:public 成员修饰符,公共的谁都可以访问。

   2:private 成员修饰符,私有的,只有自己可以访问。

   3:根据需求提供公共的方法set或者get方法获取以及设置该私有属性的值,对外提供公开的用于设置对象属性的public方法。

1.3.3封装的应用场景

如果一个属性不想被其他人直接的访问,那么这个时候就可以使用封装。现实开发中的实体类的成员属性(成员变量)一般都会封装起来。

实体类:用于描述一类事物的类则成为实体类,比如:class Car(),class Student。

public class Demo0028 {     
    public static void main(String[] args) {
        Employee boxiaoyuan = new Employee();
        boxiaoyuan.setId("111111");
        boxiaoyuan.setName("boxiaoyuan");
        boxiaoyuan.setGender("不是男");
        boxiaoyuan.work();
    }
}
class Employee{
    private String name;
    private String id;
    private String gender;
    //提供了公共的set get方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        if(gender.equals("男")||gender.equals("女")) {
            this.gender = gender;
        }else {
            System.out.println("请输入"男"或者"女"");
        }
    }

    public void work() {
        System.out.println(id+":"+name+":"+gender+"在工作");
    }
}

1.3.4封装概述

封装是面向对象三大特征之一(封装,继承,多态) 是面向对象编程语言对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界是无法直接操作的。

1.3.5封装原则

将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问 成员变量private,提供对应的getXxx()/setXxx()方法。

1.3.6封装好处

通过方法来控制成员变量的操作,提高了代码的安全性,把代码用方法进行封装,提高了代码的复用性。

1.4this

1.4.1this的概述

this关键字代表的是对象的引用,方法被哪个对象调用,this就代表哪个对象。

1.4.2this的作用

  • 一个类存在着同名的成员变量与局部变量时,在方法内部默认是访问局部变量的数据,我们可以通过this关键字访问成员变量的数据。
  • this关键字可以在构造函数中调用其他的构造函数初始化对象使用。

1.4.3this的细节

  • 如果在一个函数中访问一个成员变量,而且没有存在同名的局部变量时,那么java编译器会默认在变量的前面加上this关键字。
  • this关键字调用其他的构造函数时,this语句必须位于构造函数中的第一个语句。
  • this关键字调用构造函数的时候不准出现相互调用的情况,因为是一个死循环的调用方式。
  • this只能在非静态中(没有static修饰的)的函数中使用。

1.5构造方法

1.5.1构造方法的作用

构造方法的作用是对对象进行初始化。

public class Demo0029 {     
    public static void main(String[] args) {
        Student student = new Student("boxiaoyuan", 12);//这个对象创建出来就有了自己的名字和年龄。
        student.eat("鸡翅");
    }
}
class Student{
    private String name;
    private int age;
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void eat(String food) {
        System.out.println(name +"正在吃"+food);
    }
}

1.5.2标准类制作

  • 成员变量
    • 使用private修饰
  • 构造方法
    • 提供一个无参构造方法
    • 提供一个带多个参数的构造方法
  • 成员方法
    • 提供每一个成员变量对应的setXxx()/getXxx()
    • 提供一个显示对象信息的show()
  • 创建对象并为其成员赋值的两种方式
    • 无参构造方法创建对象后使用setXxx()赋值
    • 使用带参构造方法直接创建带有属性值的对象

1.5.3构造函数和普通的函数的区别

  • 1、一般函数是用于定义对象应该具备的功能。而构造函数定义的是:对象在调用功能之前,在建立时,应该具备的一些内容。也就是对象的初始化内容。
  • 2、构造函数是在对象建立时由jvm调用, 给对象初始化。一般函数是对象建立后,当对象调用该功能时才会执行。(构造方法不是java虚拟机添加的,是java编译器添加的)
  • 3、普通函数可以使用对象多次调用,构造函数就在创建对象时调用。
  • 4、构造函数的函数名要与类名一样,而普通的函数只要符合标识符的命名规则即可。
  • 5、构造函数没有返回值类型。无参的构造函数的权限修饰符是与类一致的。

注意细节:

  • 1.当类中没有定义构造函数时,系统会自动给该类加上一个空参数的构造函数。这个是类中默认的构造函数。当类中如果自定义了构造函数,这时默认的构造函数就没有了。
  • 2.在一个类中可以定义多个构造函数,以进行不同的初始化。多个构造函数存在于类中,是以重载的形式体现的。因为构造函数的名称都相同。

1.5.4构造代码块

构造代码块作用:给所有的对象进行统一的初始化。

执行顺序:

  • 基类静态代码块
  • 派生类中的静态代码块
  • 基类代码块
  • 基类无参构造方法
  • 派生类中的代码块
  • 派生类中的无参构造方法
  • 派生类中的方法
package com.boxiaoyuan.www;

public class Father {
    {
        System.out.println("这是父类代码块");
    }
    static {
        System.out.println("这是父类静态代码块");
    }
    public Father() {
        System.out.println("这是父类构造方法");
    }
}

package com.boxiaoyuan.www;

public class Son extends Father{
    {
        System.out.println("这是子类代码块");
    }
    static {
        System.out.println("这是子类静态代码块");
    }
    public Son() {
        System.out.println("这是子类构造函数");
    }
}

package com.boxiaoyuan.www;

public class Demo05 {
    public static void main(String[] args) {
        Son son = new Son();
    }
}


-------输出结果--------
这是父类静态代码块
这是子类静态代码块
这是父类代码块
这是父类构造方法
这是子类代码块
这是子类构造函数

构造代码块要注意的细节:

  • 1构造函数的代码是位于成员变量的显示初始化语句、构造代码块语句之后执行的。
  • 2成员变量的显式初始化语句与构造代码块的语句的先后执行顺序是按照当前代码的顺序执行的。
  • 3成员变量的初始化语句和构造代码块的代码其实是在构造函数中完成的。

1.6继承

1:描述类和类之间的关系。

2:降低类和类之间的重复代码:

  • 降低对象和对象之间的代码重复使用静态变量
  • 降低类和类之间的代码重复使用继承
package com.boxiaoyuan.www;

public class Person{
    private String name;
    public Person(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    
    public void speak() {
        System.out.println(this.name+":我是人");
    }
}

package com.boxiaoyuan.www;

public class Student extends Person{

    public Student(String name) {
        super(name);
    }
    public void study() {
        System.out.println("姓名:" + this.getName() + ":好好学习,天天向上");
    }
}

package com.boxiaoyuan.www;

public class Worker extends Student{
    public Worker(String name) {
        super(name);
    }
    public void work() {
        System.out.println("好好工作,天天挣钱");
    }
}

package com.boxiaoyuan.www;

public class Demo04 {
    public static void main(String[] args) {
        Student s = new Student("张三");
        s.study();
        Worker worker = new Worker("李四");
        worker.work();
    }
}

继承细节:

   1:类名的设定,被继承的类称之为父类(基类),继承的类称之为子类

   2:子类可以有父类的内容,子类还可以有自己特有的内容

   3:子类并不能继承父类中所有的成员

      1:所有的私有成员不能继承。

      2:构造函数不能被继承

 4:什么时候使用继承

  继承体现的关系:is a,如有两个类A和B,如果满足A是B的一种,或者B是A的一种,就说明存在继承关系,如:苹果是水果的一种,猫是动物的一种。

    5:子类显式调用父类构造函数:

  在子类构造函数第一行通过super关键字调用父类任何构造函数。如果显式调用父类构造函数,编译器自动添加的调用父类无参数的构造就消失。构造函数间的调用只能放在第一行,只能调用一次。super()和this()不能同时存在构造函数第一行。

   6:继承中成员方法的访问特点:

  通过子类对象访问一个方法,首先在子类成员范围找,然后在父类成员范围找,如果都没有则报错(不考虑父亲的父亲)。

   7:Java中类只支持单继承,不支持多继承,但是支持多层继承。

1.7重写

在继承中,子类可以定义和父类相同的名称且参数列表一致的函数,将这种函数称之为函数的重写。

细节:

1:函数名必须相同

2:参数列表必须相同

3:子类重写父类的函数的时候,函数的访问权限必须大于等于父类的函数的访问权限否则编译报错

4:子类重写父类的函数的时候,返回值类型必须是父类函数的返回值类型或该返回值类型的子类。不能返回比父类更大的数据类型:如子类函数返回值类型是Object

重载和重写的不同:

1:重载(overload): 

   1:前提: 所有的重载函数必须在同一个类中

   2:特点:

         函数名相同,参数列表不同,与其他的无关(访问控制符、返回值类型)

   3:不同:

          个数不同、顺序不同、类型不同

2:重写(override):

       1:前提: 继承

       2:特点:

          函数名必须相同、参数列表必须相同

          子类的返回值类型要等于或者小于父类的返回值

1.8包

1.8.1包的概述和使用

包其实就是文件夹,其作用就是对类进行分类管理。

1.8.2包的定义格式

  • 格式:package 包名;(多级包用.分开)
  • 范例:package com.boxiaoyaun;

1.8.3带包的Java类编译和执行

  • 手动建包
    • 按照以前的格式编译java文件      javac HelloWorld.java
    • 手动创建包    在E盘建立文件夹com,然后在com下建立文件夹boxiaoyuan
    • 把class文件放到包的最里面     把HelloWorld.class文件放到com下的boxiaoyuan文件夹下
    • 带包执行  java com.boxiaoyuan.HelloWorld
  • 自动建包
    • javac -d . HelloWorld.java
    • java com.boxiaoyuan.HelloWorld

1.8.4导包

使用不同包下的类时,使用的时候要写类的全路径,这样很麻烦,为了简化带包的操作,Java提供了导包的功能。

导包的格式:

  • 格式:import 包名;
  • 范例:import com.boxiaoyuan.Teacher

1.9权限修饰符

protected修饰符所修饰的类(这句话中指父类)的成员变量和方法,只可以被子类访问,而不管子类是不是和父类位于同一个包中;default修饰符所修饰的类属成员变量和方法,只可被同一个包中的其他类访问,而不管其他类是不是该类的子类。protected属于子类限制修饰符,而default属于包限制修饰符。

1.10final

final关键字主要用于修饰类、类成员、方法以及方法的形参。

  • 修饰类
    • 当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。在使用final修饰类的时候,要注意谨慎选择,除非这个类真的在以后不会用来继承或者出于安全的考虑,尽量不要将类设计为final类。
  • 修饰方法
    • 该方法是最终方法,不能被重写,当一个类被继承,那么所有的非私有函数都将被继承,如果函数不想被子类继承并重写可以将该函数final修饰,当一个类中的函数都被修饰为final时,可以将类定义为final的。
  • 修饰变量
    • 对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。
  • 修饰形参
    • 当形参被修饰为final,那么该形参所属的方法中不能被篡改,项目中主要用于一些只用来遍历未知数据的函数。将未知变量声明为final的。增强数据的安全性。

1.11static

  • 1:用于修饰类的成员
    • 1:成员变量
      • 1:非静态成员变量:需要创建对象来访问。
      • 2:静态成员变量:使用类名直接调用,也可以通过对象访问,推荐使用类名访问。
      • 3:千万不要为了方便访问而使用static修饰一个成员变量,只有这个成员变量的数据是需要被共享的时候才使用static修饰。
    • 2:成员方法,静态函数,可以使用类名直接调用
      • 1:静态函数中不能访问非静态成员变量,只能访问静态变量
      • 2:静态方法不可以定义this,super关键字
      • 3:因为静态优先于对象存在.静态方法中更不可以出现this
      • 4:非静态函数中可以访问静态成员变量

细节:

  • 1:静态函数中可以直接访问静态的成员,但是不能直接访问非静态的成员。
  • 2:非静态函数可以访问静态变量以及非静态的成员。
    • 原因:静态函数可以使用类名调用,而这时候对象可能还没存在内存中,这时候非静态的数据也就不存在了。
  • 3:非静态的函数只能使用对象调用,不能使用类名调用。
    • 原因:非静态函数必须要由对象调用,如果对象存在了,静态数据以及非静态数据早就存在内存中了。
  • 4:静态函数不能出现this以及super关键字。
    • 原因:因为静态函数可以使用类名直接调用,而这时候可能还没有对象存在,this又代表当前对象。

1.11多态

1:什么是多态

      父类引用指向子类对象,调用方法时会调用子类的实现,而不是父类的实现。

2:多态的前提:必须存在继承或者实现关系。

3:多态要注意的细节:

  • 1:多态情况下,子父类存在同名的成员变量时,默认会访问父类的成员变量。
  • 2:多态情况下,子父类存在同名的非静态函数时,默认是访问子类的成员函数。
  • 3:多态情况下,子父类存在同名的静态函数时,默认是访问父类的成员函数。
  • 4:多态情况下,不能访问子类特有的成员。

      总结:多态情况下,子父类存在同名的成员时,默认都会访问父类的成员,只有存在非静态的同名函数时,才是访问子类的成员。

多态情况下如果需要调用到子类特有的成员,那么需要进行类型转换。

实例

public abstract class Animal {
    abstract void eat();
}

public class Cat extends Animal{

    @Override
    public void eat() {
        System.out.println("吃鱼");
    }
    public void catchMouse() {
        System.out.println("抓老鼠");
    }
}

public class Dog extends Animal{

    @Override
    void eat() {
        System.out.println("吃骨头");
    }
    public void lookDoor() {
        System.out.println("看家门");
    }
}

public class Demo01 {
    public static void main(String[] args) {
        testFunc(new Cat());
        testFunc(new Dog());
        Animal animal = new Dog(); //向上转型
        animal.eat();
        
        Dog d = (Dog)animal;  //向下转型
        d.lookDoor();
    }
    
    public static void testFunc(Animal animal) {
        if(animal instanceof Cat) {
            Cat c = (Cat)animal;
            c.catchMouse();
        }else if(animal instanceof Dog) {
            Dog d = (Dog)animal;
            d.lookDoor();
        }
    }
}

1.12抽象类

抽象类的特点

  • 1:有抽象函数的类,该类一定是抽象类。
  • 2:抽象类中不一定要有抽象函数。
  • 3:抽象类不能使用new创建对象。
  • 4:抽象类主要为了提高代码的复用性,让子类继承来使用。
  • 5:编译器强制子类实现抽象类父类的未实现的方法。
    • 1:可以不实现,前提是子类的也要声明为抽象的。
public abstract class Animal {
    public abstract void cry();
}

public class Cat extends Animal{
    @Override
    public void cry() {
        System.out.println("猫叫:喵喵...");
    }
}

public class Dog extends Animal {
    @Override
    public void cry() {
        System.out.println("狗叫:汪汪...");
    }
}

public class Demo {
    public static void main(String[] args) {
        Animal a1 = new Dog();
        Animal a2 = new Cat();
        a1.cry();
        a2.cry();
    }
}

抽象类注意细节

    • 1:如果一个方法没有方法体,那么该方法必须使用abstract修饰。
    • 2:如果一个类有抽象的方法,那么该类也必须使用abstract修饰。
    • 3:非抽象类继承抽象类的时候,必须要把抽象类中的所有抽象方法全部实现。
    • 4:抽象类可以定义抽象方法以及非抽象方法,抽象类可以没有抽象方法(java.awt.*的类就是这样子操作的)。
    • 5:抽象类是可以不存在抽象方法的(不常用,没意义)。
    • 6:抽象类不能创建对象。
      • 因为抽象类一旦创建了对象就可以使用对象去调用方法了,一旦调用了抽象方法就没有任何的意义了。
    • 7:抽象类是存在构造方法的,抽象类一定有构造方法。
    • 抽象类的构造方法是留给子类调用初始化从父类继续下去的成员变量的
  • 8:抽象类可以继承普通类与抽象类。

abstract与其他修饰符的关系

  • finalabstract不能共存:
    • final:它的作用是修饰类代表不可以继承,修饰方法不可重写。
    • abstract修饰类就是用来被继承的,修饰方法就是用来被重写的。
  • static修饰的方法可以用类名调用,对于abstract修饰的方法没有具体的方法实现,所有不能直接调用,也就是说abstract不可以与static共存。
  • privateabstract不能共存:
    • private修饰的只能在本类中使用。
    • abstract修饰的方法是用来被子类进行重写的,有矛盾,所有不能共存。

1.13接口

1.13.1接口概述

接口就是一种公共的规范标准,只要符合规范标准,大家都可以通用,Java中的接口更多的体现在对行为的抽象。

1.13.2接口的特点

  • 1.类实现接口可以通过implements实现,实现接口的时候必须把接口中的所有方法实现,一个类可以实现多个接口。
  • 2.接口中定义的所有的属性默认是public static final的,即静态常量,既然是常量,那么定义的时候必须赋值。
  • 3.接口中定义的方法不能有方法体。接口中定义的方法默认添加public abstract
  • 4.有抽象函数的不一定是抽象类,也可以是接口类。
  • 5.由于接口中的方法默认都是抽象的,所以不能被实例化。
  • 6.对于接口而言,可以使用子类来实现接口中未被实现的功能函数。
  • 7.如果实现类中要访问接口中的成员,不能使用super关键字。因为两者之间没有显示的继承关系,况且接口中的成员属性是静态的。可以使用接口名直接访问。
  • 8.接口没有构造方法。

1.14匿名对象

匿名对象:没有名字的对象。

  • 1.当对象对方法仅进行一次调用的时候,可以使用匿名对象。
  • 2.匿名对象可以作为实际参数进行传递。
package com.boxiaoyuan.www;

public class Car {
    private String name;
    private String color;
    private int num;
    public Car(String name, String color, int num) {
        this.name = name;
        this.color = color;
        this.num = num;
    }
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public void run() {
        System.out.println(this.name + this.color + this.num + "轮车在跑");
    }
}


package com.boxiaoyuan.www;

public class CarDemo {
    public static void main(String[] args) {
        CarFactory cFactory = new CarFactory("4S店", "北京市朝阳区");
        Car c = cFactory.repareCar(new Car("宝马", "白色", 3) , "黑色", 4);
        c.run();
    }
}


package com.boxiaoyuan.www;

public class CarFactory {
    private String name;
    private String address;
    
    public CarFactory(String name, String address) {
        this.name = name;
        this.address = address;
    }
    public Car repareCar(Car c, String color, int num) {
        c.setColor(color);
        c.setNum(num);
        return c;
    }
}

总结:

       1. 匿名对象设置的属性永远无法获取,因为没有引用变量指向那个对象。

       2. 任何两个匿名对象使用==比较,永远返回false(两个匿名对象不可能是同一个对象)。

       3.  匿名对象主要应用于实参。

       4. 一般不会给匿名对象赋予属性值,因为无法获取到。

1.15instanceof

instanceof是什么?

  • 1:属于比较运算符。
  • 2:instanceof关键字:该关键字用来判断一个对象是否是指定类的对象。
  • 3:用法:
    • 对象  instanceof 类;  
    • 该表达式是一个比较运算符,返回的结果是boolea类型  true|false
  • 4:注意:使用instanceof关键字做判断时,两个类之间必须有关系。

16内部类

16.1内部类概述

内部类:就是在一个类中定义一个类。举例:在一个类A的内部定义一个类B,类B就被称为内部类。

public class 类名 {
     修饰符 class 类名 {
    }
}

16.2访问特点

  • 内部类可以直接访问外部类的成员,包括私有;
  • 外部类要访问内部类的成员,必须创建对象;
public class Outer {
    private int num = 10;
    public class Inner {
        public void show() {
            System.out.println(num);
        }
    }
    public void method() {
        Inner i = new Inner();
        i.show();
    }
}

16.3成员内部类

  1. 定义位置:在类中方法外,跟成员变量是一个位置。
  2. 使用方式:将一个类,设计为内部类的目的,大多数都是不想让外界去访问,所以内部类的定义应该私有化,私有化之后,再提供一个可以让外界调用的方法,方法内部创建内部类对象并调用。
class Outer {
    private int num = 10;
    private class Inner {
        public void show() {
            System.out.println(num);
        }
    }
    public void method() {
        Inner i = new Inner();
        i.show();
    }
}
public class InnerDemo {
    public static void main(String[] args) {
        //Outer.Inner oi = new Outer().new Inner();
        //oi.show();
        Outer o = new Outer();
        o.method();
    }
}

16.4局部内部类

  1. 定义位置:局部内部类是在方法中定义的类;
class Outer {
    private int num = 10;
    public void method() {
        int num2 = 20;
        class Inner {
            public void show() {
                System.out.println(num);
                System.out.println(num2);
            }
        }
    }
}

        2.使用方式:局部内部类,外界是无法直接使用,需要在方法内部创建对象并使用,该类可以直接访问外部类的成员,也可以访问方法内的局部变量。

class Outer {
    private int num = 10;
    public void method() {
        int num2 = 20;
        class Inner {
            public void show() {
                System.out.println(num);
                System.out.println(num2);
            }
        }
        Inner i = new Inner();
        i.show();
    }
}
public class OuterDemo {
    public static void main(String[] args) {
        Outer o = new Outer();
        o.method();
    }
}

局部内部类所用的局部变量要用final修饰,java8中不需要使用final修饰,但是局部变量不能被修改。

public class InnerDemo {
    public static void main(String[] args) {
        start();
    }
    public static void start(){
        int localvariable=5;
        class A{
            public void print(){
                localvariable = localvariable +1;
            }
        }

        A a = new A();
        a.print();
    }
}

16.5匿名内部类

  • 定义匿名内部类的前提:存在一个类或者接口,这里的类可以是具体类也可以是抽象类。
  • 格式:
new 类名 ( ) { 
    重写方法 
} 
new 接口名 ( ) { 
    重写方法 
}
  • 本质:匿名内部类是一个继承了该类或者实现了该接口的子类匿名对象。
  • 使用方式:
    • 通过多态的形式接受
Inter i = new Inter(){
    @Override
    public void method(){
        
    }
}
    • 直接调用方法
interface Inter{
    void method();
}

class Test{
    public static void main(String[] args){
        new Inter(){
            @Override
            public void method(){
                System.out.println("我是匿名内部类");
            }
        }.method();    // 直接调用方法
    }
}
原文地址:https://www.cnblogs.com/zhuzhaoli/p/10847724.html