第五章 java面向对象进阶 Day3

5 篇文章 0 订阅

以下笔记来源 www.sxt.cn 仅供自己学习,做笔记,不做商业用途。侵删。

5.1 概述

本章重点针对面向对象的三大特征:继承、封装、多态进行详细的讲解。另外还包括抽象类、接口、内部类等概念。很多概念对于初学者来说,更多的是先进行语法性质的了解。不要期望,通过本章学习就“搞透面向对象”。本章只是面向对象的起点,后面所有的章节说白了都是对面向对象这一章的应用。

5.1.1 继承的实现

在我们编程中,如果新定义一个Student类,发现已经有Person类包含了我们需要的属性和方法,那么Student类只需要继承Person类即可拥有Person类的属性和方法。
【示例5-1】使用extends实现继承

public class Test{
    public static void main(String[] args) {
        Student s = new Student("高淇",172,"Java");
        s.rest();
        s.study();
    }
}
class Person {
    String name;
    int height;
    public void rest(){
        System.out.println("休息一会!");
    }  
}
class Student extends Person {//继承Person里面的一些属性和方法
    String major; //专业
    public void study(){
        System.out.println("在尚学堂,学习Java");
    }  
    public Student(String name,int height,String major) {
        //天然拥有父类的属性
        this.name = name;
        this.height = height;
        this.major = major;
    }
}
/*
输出示例
休息一会儿!
在尚学堂,学习java。
*/
5.1.2 instanceof 运算符

instanceof是二元运算符,左边是对象,右边是类;当对象是右面类或子类所创建对象时,返回true;否则,返回false。比如:
【示例5-2】使用instanceof运算符进行类型判断

public class Test{
    public static void main(String[] args) {
        Student s = new Student("高淇",172,"Java");
        System.out.println(s instanceof Person);
        System.out.println(s instanceof Student);
    }
}

两条语句的输出结果都是true。

5.1.3 继承使用要点

1.父类也称作超类、基类、派生类等。

2.Java中只有单继承,没有像C++那样的多继承。多继承会引起混乱,使得继承链过于复杂,系统难于维护。

3.Java中类没有多继承,接口有多继承。

4.子类继承父类,可以得到父类的全部属性和方法 (除了父类的构造方法),但不见得可以直接访问(比如,父类私有的属性和方法)。

5.如果定义一个类时,没有调用extends,则它的父类是:java.lang.Object。

5.1.4方法的重写override

子类通过重写父类的方法,可以用自身的行为替换父类的行为。方法的重写是实现多态的必要条件。

方法的重写需要符合下面的三个要点:

  1.“==”: 方法名、形参列表相同。

  2.“≤”:返回值类型和声明异常类型,子类小于等于父类。

  3.“≥”: 访问权限,子类大于等于父类。

方法重写

public class TestOverride {
    public static void main(String[] args) {
        Vehicle v1 = new Vehicle();
        Vehicle v2 = new Horse();
        Vehicle v3 = new Plane();
        v1.run();
        v2.run();
        v3.run();
        v2.stop();
        v3.stop();
    }
}
 
class Vehicle { // 交通工具类
    public void run() {
        System.out.println("跑....");
    }
    public void stop() {
        System.out.println("停止不动");
    }
}
class Horse extends Vehicle { // 马也是交通工具
    public void run() { // 重写父类方法
        System.out.println("四蹄翻飞,嘚嘚嘚...");
    }
}
 
class Plane extends Vehicle {
    public void run() { // 重写父类方法
        System.out.println("天上飞!");
    }
    public void stop() {
        System.out.println("空中不能停,坠毁了!");
    }
}  

在这里插入图片描述

5.2.1 Object类基本特性

Object类是所有Java类的根基类,也就意味着所有的Java对象都拥有Object类的属性和方法。如果在类的声明中未使用extends关键字指明其父类,则默认继承Object类。

5.2.2 toString方法

Object类中定义有public String toString()方法,其返回值是 String 类型。Object类中toString方法的源码为:

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

根据如上源码得知,默认会返回“类名+@+16进制的hashcode”。在打印输出或者用字符串连接对象时,会自动调用该对象的toString()方法。
【示例5-5】toString()方法测试和重写toString()方法

class Person {
    String name;
    int age;
    @Override
    public String toString() {
        return name+",年龄:"+age;
    }
}
public class Test {
    public static void main(String[] args) {
        Person p=new Person();
        p.age=20;
        p.name="李东";
        System.out.println("info:"+p);
         
        Test t = new Test();
        System.out.println(t);
    }
}

在这里插入图片描述

5.2.3 ==和equals方法

“==”代表比较双方是否相同。如果是基本类型则表示值相等,如果是引用类型则表示地址相等即是同一个对象。

Object 的 equals 方法默认就是比较两个对象的hashcode,是同一个对象的引用时返回 true 否则返回 false。但是,我们可以根据我们自己的要求重写equals方法。

【示例5-6】equals方法测试和自定义类重写equals方法

public class TestEquals { 
    public static void main(String[] args) {
        Person p1 = new Person(123,"高淇");
        Person p2 = new Person(123,"高小七");     
        System.out.println(p1==p2);     //false,不是同一个对象
        System.out.println(p1.equals(p2));  //true,id相同则认为两个对象内容相同
        String s1 = new String("尚学堂");
        String s2 = new String("尚学堂");
        System.out.println(s1==s2);         //false, 两个字符串不是同一个对象
        System.out.println(s1.equals(s2));  //true,  两个字符串内容相同
    }
}
class Person {
    int id;
    String name;
    public Person(int id,String name) {
        this.id=id;
        this.name=name;
    }
    public boolean equals(Object obj) {
        if(obj == null){
            return false;
        }else {
            if(obj instanceof Person) {
                Person c = (Person)obj;
                if(c.id==this.id) {
                    return true;
                }
            }
        }
        return false;
    }
}

JDK提供的一些类,如String、Date、包装类等,重写了Object的equals方法,调用这些类的equals方法, x.equals (y) ,当x和y所引用的对象是同一类对象且属性内容相等时(并不一定是相同对象),返回 true 否则返回 false。

5.3 super关键字

super是直接父类对象的引用。可以通过super来访问父类中被子类覆盖的方法或属性。

使用super调用普通方法,语句没有位置限制,可以在子类中随便调用。

若是构造方法的第一行代码没有显式的调用super(…)或者this(…);那么Java默认都会调用super(),含义是调用父类的无参数构造方法。这里的super()可以省略。

public class TestSuper01 { 
    public static void main(String[] args) {
        new ChildClass().f();
    }
}
class FatherClass {
    public int value;
    public void f(){
        value = 100;
        System.out.println ("FatherClass.value="+value);
    }
}
class ChildClass extends FatherClass {
    public int value;
    public void f() {
        super.f();  //调用父类对象的普通方法
        value = 200;
        System.out.println("ChildClass.value="+value);
        System.out.println(value);
        System.out.println(super.value); //调用父类对象的成员变量
    }
}

在这里插入图片描述

5.3.1 继承树追溯

·属性/方法查找顺序:(比如:查找变量h)

  1. 查找当前类中有没有属性h

  2. 依次上溯每个父类,查看每个父类中是否有h,直到Object

  3. 如果没找到,则出现编译错误。

  4. 上面步骤,只要找到h变量,则这个过程终止。

·构造方法调用顺序:
构造方法第一句总是:super(…)来调用父类对应的构造方法。所以,流程就是:先向上追溯到Object,然后再依次向下执行类的初始化块和构造方法,直到当前子类为止。

  注:静态初始化块调用顺序,与构造方法调用顺序一样,不再重复。
5.4.1 封装的作用和含义

需要让用户知道的才暴露出来,不需要让用户知道的全部隐藏起来,这就是封装。说的专业一点,封装就是把对象的属性和操作结合为一个独立的整体,并尽可能隐藏对象的内部实现细节。

我们程序设计要追求“高内聚,低耦合”。 高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合是仅暴露少量的方法给外部使用,尽量方便外部调用。

编程中封装的具体优点:

 1. 提高代码的安全性。

 2. 提高代码的复用性。

 3. “高内聚”:封装细节,便于修改内部代码,提高可维护性。

 4. “低耦合”:简化外部调用,便于调用者使用,便于扩展和协作。
5.4.2 封装的实现—使用访问控制符

在这里插入图片描述

  1. private 表示私有,只有自己类能访问

  2. default表示没有修饰符修饰,只有同一个包的类能访问

  3. protected表示可以被同一个包的类以及其他包中的子类访问

  4. public表示可以被该项目的所有包中的所有类访

  5. public修饰符的访问权限为:该项目的所有包中的所有类。

  6. protected修饰符的访问权限为:同一个包中的类以及其他包中的子类。

  7. private修饰符的访问权限为:同一个类。

5.4.3 封装的使用细节

类的属性的处理:

  1. 一般使用private访问权限。

  2.  提供相应的get/set方法来访问相关属性,这些方法通常是public修饰的,以提供对属性的赋值与读取操作(注意:boolean变量的get方法是is开头!)。

  3. 一些只用于本类的辅助性方法可以用private修饰,希望其他类调用的方法用public修饰。

【示例5-10】JavaBean的封装实例

public class Person {
    // 属性一般使用private修饰
    private String name;
    private int age;
    private boolean flag;
    // 为属性提供public修饰的set/get方法
    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 boolean isFlag() {// 注意:boolean类型的属性get方法是is开头的
        return flag;
    }
    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}

【示例5-11】封装的使用

class Person {
    private String name;
    private int age;
    public Person() {
 
    }
    public Person(String name, int age) {
        this.name = name;
        // this.age = age;//构造方法中不能直接赋值,应该调用setAge方法
        setAge(age);
    }
     
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setAge(int age) {
        //在赋值之前先判断年龄是否合法
        if (age > 130 || age < 0) {
            this.age = 18;//不合法赋默认值18
        } else {
            this.age = age;//合法才能赋值给属性age
        }
    }
    public int getAge() {
        return age;
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}
 
public class Test2 {
    public static void main(String[] args) {
        Person p1 = new Person();
        //p1.name = "小红"; //编译错误
        //p1.age = -45;  //编译错误
        p1.setName("小红");
        p1.setAge(-45);
        System.out.println(p1);
         
        Person p2 = new Person("小白", 300);
        System.out.println(p2);
    }
}

5.5 多态(polymorphism)

多态指的是同一个方法调用,由于对象不同可能会有不同的行为。现实生活中,同一个方法,具体实现会完全不同。 比如:同样是调用人的“休息”方法,张三是睡觉,李四是旅游,高淇老师是敲代码,数学教授是做数学题; 同样是调用人“吃饭”的方法,中国人用筷子吃饭,英国人用刀叉吃饭,印度人用手吃饭。

多态的要点:

  1. 多态是方法的多态,不是属性的多态(多态与属性无关)。

  2. 多态的存在要有3个必要条件:继承,方法重写,父类引用指向子类对象。

  3. 父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了。

【示例5-12】多态和类型转换测试

 class Animal {
    public void shout() {
        System.out.println("叫了一声!");
    }
}
class Dog extends Animal {
    public void shout() {
        System.out.println("旺旺旺!");
    }
    public void seeDoor() {
        System.out.println("看门中....");
    }
}
class Cat extends Animal {
    public void shout() {
        System.out.println("喵喵喵喵!");
    }
}
public class TestPolym {
    public static void main(String[] args) {
        Animal a1 = new Cat(); // 向上可以自动转型
        //传的具体是哪一个类就调用哪一个类的方法。大大提高了程序的可扩展性。
        animalCry(a1);
        Animal a2 = new Dog();
        animalCry(a2);//a2为编译类型,Dog对象才是运行时类型。
         
        //编写程序时,如果想调用运行时类型的方法,只能进行强制类型转换。
        // 否则通不过编译器的检查。
        Dog dog = (Dog)a2;//向下需要强制类型转换
        dog.seeDoor();
    }
 
    // 有了多态,只需要让增加的这个类继承Animal类就可以了。
    static void animalCry(Animal a) {
        a.shout();
    }
 
    /* 如果没有多态,我们这里需要写很多重载的方法。
     * 每增加一种动物,就需要重载一种动物的喊叫方法。非常麻烦。
    static void animalCry(Dog d) {
        d.shout();
    }
    static void animalCry(Cat c) {
        c.shout();
    }*/
}

5.6 对象的转型(casting)

父类引用指向子类对象,我们称这个过程为向上转型,属于自动类型转换。
向上转型后的父类引用变量只能调用它编译类型的方法,不能调用它运行时类型的方法。这时,我们就需要进行类型的强制转换,我们称之为向下转型!

public class TestCasting {
    public static void main(String[] args) {
        Object obj = new String("北京尚学堂"); // 向上可以自动转型
        // obj.charAt(0) 无法调用。编译器认为obj是Object类型而不是String类型
        /* 编写程序时,如果想调用运行时类型的方法,只能进行强制类型转换。
         * 不然通不过编译器的检查。 */
        String str = (String) obj; // 向下转型
        System.out.println(str.charAt(0)); // 位于0索引位置的字符
        System.out.println(obj == str); // true.他们俩运行时是同一个对象
    }
}

类型转换异常

public class TestCasting2 {
    public static void main(String[] args) {
        Object obj = new String("北京尚学堂");
        //真实的子类类型是String,但是此处向下转型为StringBuffer
        StringBuffer str = (StringBuffer) obj;
        System.out.println(str.charAt(0));
    }
}

为了避免出现这种异常,我们可以使用5.1.2中所学的instanceof运算符进行判断,如示例5-15所示。

public class TestCasting3 {
    public static void main(String[] args) {
        Object obj = new String("北京尚学堂");
        if(obj instanceof String){
            String str = (String)obj;
            System.out.println(str.charAt(0));
        }else if(obj instanceof StringBuffer){
            StringBuffer str = (StringBuffer) obj;
            System.out.println(str.charAt(0));
        }
    }
}

5.7 final关键字

final关键字的作用:

  1. 修饰变量: 被他修饰的变量不可改变。一旦赋了初值,就不能被重新赋值。
    final int MAX_SPEED = 120;
  2. 修饰方法:该方法不可被子类重写。但是可以被重载!
    final void study(){}
  3. 修饰类: 修饰的类不能被继承。比如:Math、String等。
    final class A {}

5.8 抽象方法和抽象类

抽象方法

使用abstract修饰的方法,没有方法体,只有声明。定义的是一种“规范”,就是告诉子类必须要给抽象方法提供具体的实现。

抽象类

包含抽象方法的类就是抽象类。通过abstract方法定义规范,然后要求子类必须定义具体实现。通过抽象类,我们就可以做到严格限制子类的设计,使子类之间更加通用。

【示例5-16】抽象类和抽象方法的基本用法

//抽象类
abstract class Animal {
    abstract public void shout();  //抽象方法
}
class Dog extends Animal { 
    //子类必须实现父类的抽象方法,否则编译错误
    public void shout() {
        System.out.println("汪汪汪!");
    }
    public void seeDoor(){
        System.out.println("看门中....");
    }
}
//测试抽象类
public class TestAbstractClass {
    public static void main(String[] args) {
        Dog a = new Dog();
        a.shout();
        a.seeDoor();
    }
}

抽象类的使用要点:

  1. 有抽象方法的类只能定义成抽象类

  2. 抽象类不能实例化,即不能用new来实例化抽象类。

  3. 抽象类可以包含属性、方法、构造方法。但是构造方法不能用来new实例,只能用来被子类调用。

  4. 抽象类只能用来被继承。

  5. 抽象方法必须被子类实现。

5.9.1接口的作用

这一节有点懵逼,只晓得接口比抽象还抽象,我懵了。
接口这一块儿学的有点晕,跟对象的调用也差不多吧,为啥就不是一个东西了,为啥就要用接口呢。
接口 —— 静态——不变——框架?
不是很懂。
这些是疑惑。
下面的内部类也有点蒙圈。

5.9.2 如何定义和使用接口?

定义接口的详细说明:

  1. 访问修饰符:只能是public或默认。

  2. 接口名:和类名采用相同命名机制。

  3. extends:接口可以多继承。

  4. 常量:接口中的属性只能是常量,总是:public static final 修饰。不写也是。

  5. 方法:接口中的方法只能是:public abstract。 省略的话,也是public abstract。

要点

  1. 子类通过implements来实现接口中的规范。

  2. 接口不能创建实例,但是可用于声明引用变量类型。

  3. 一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是public的。

  4. JDK1.7之前,接口中只能包含静态常量、抽象方法,不能有普通属性、构造方法、普通方法。

  5. JDK1.8后,接口中包含普通的静态方法。

【示例5-17】接口的使用

public class TestInterface {
    public static void main(String[] args) {
        Volant volant = new Angel();
        volant.fly();
        System.out.println(Volant.FLY_HIGHT);
         
        Honest honest = new GoodMan();
        honest.helpOther();
    }
}
/**飞行接口*/
interface Volant { 
    int FLY_HIGHT = 100;  // 总是:public static final类型的;
    void fly();   //总是:public abstract void fly();
}
/**善良接口*/
interface Honest { 
    void helpOther();
}
/**Angle类实现飞行接口和善良接口*/
class Angel implements Volant, Honest{
    public void fly() {
        System.out.println("我是天使,飞起来啦!");
    }
    public void helpOther() {
        System.out.println("扶老奶奶过马路!");
    }
}
class GoodMan implements Honest {
   public void helpOther() {
        System.out.println("扶老奶奶过马路!");
    }  
}
class BirdMan implements Volant {
    public void fly() {
        System.out.println("我是鸟人,正在飞!");
    }
}

在这里插入图片描述

5.9.3 接口的多继承

接口完全支持多继承。和类的继承类似,子接口扩展某个父接口,将会获得父接口中所定义的一切。

【示例5-18】接口的多继承

interface A {
    void testa();
}
interface B {
    void testb();
}
/**接口可以多继承:接口C继承接口A和B*/
interface C extends A, B {
    void testc();
}
public class Test implements C {
    public void testc() {
    }
    public void testa() {
    }
    public void testb() {
    }
}
5.9.4 面向接口编程

面向接口编程是面向对象编程的一部分。

为什么需要面向接口编程? 软件设计中最难处理的就是需求的复杂变化,需求的变化更多的体现在具体实现上。我们的编程如果围绕具体实现来展开就会陷入”复杂变化”的汪洋大海中,软件也就不能最终实现。我们必须围绕某种稳定的东西开展,才能以静制动,实现规范的高质量的项目。

接口就是规范,就是项目中最稳定的东东! 面向接口编程可以让我们把握住真正核心的东西,使实现复杂多变的需求成为可能。

通过面向接口编程,而不是面向实现类编程,可以大大降低程序模块间的耦合性,提高整个系统的可扩展性和和可维护性。

面向接口编程的概念比接口本身的概念要大得多。设计阶段相对比较困难,在你没有写实现时就要想好接口,接口一变就乱套了,所以设计要比实现难!

5.10.1内部类的概念

一般情况,我们把类定义成独立的单元。有些情况下,我们把一个类放在另一个类的内部定义,称为内部类(innerclasses)。

内部类可以使用public、default、protected 、private以及static修饰。而外部顶级类(我们以前接触的类)只能使用public和default修饰。

注意
内部类只是一个编译时概念,一旦我们编译成功,就会成为完全不同的两个类。对于一个名为Outer的外部类和其内部定义的名为Inner的内部类。编译完成后会出现Outer.class和Outer$Inner.class两个类的字节码文件。所以内部类是相对独立的一种存在,其成员变量/方法名可以和外部类的相同。

【示例5-19】内部类介绍

/**外部类Outer*/
class Outer {
    private int age = 10;
    public void show(){
        System.out.println(age);//10
    }
    /**内部类Inner*/
    public class Inner {
        //内部类中可以声明与外部类同名的属性与方法
        private int age = 20;
        public void show(){
            System.out.println(age);//20
        }
    }
}

内部类的作用

  1. 内部类提供了更好的封装。只能让外部类直接访问,不允许同一个包中的其他类直接访问。

  2. 内部类可以直接访问外部类的私有属性,内部类被当成其外部类的成员。 但外部类不能访问内部类的内部属性。

  3. 接口只是解决了多重继承的部分问题,而内部类使得多重继承的解决方案变得更加完整。

内部类的使用场合:

  1. 由于内部类提供了更好的封装特性,并且可以很方便的访问外部类的属性。所以,在只为外部类提供服务的情况下可以优先考虑使用内部类。

  2. 使用内部类间接实现多继承:每个内部类都能独立地继承一个类或者实现某些接口,所以无论外部类是否已经继承了某个类或者实现了某些接口,对于内部类没有任何影响。

5.10.2内部类的分类

在Java中内部类主要分为成员内部类(非静态内部类、静态内部类)、匿名内部类、局部内部类。

成员内部类(可以使用private、default、protected、public任意进行修饰。 类文件:外部类$内部类.class)

a) 非静态内部类(外部类里使用非静态内部类和平时使用其他类没什么不同)

i. 非静态内部类必须寄存在一个外部类对象里。因此,如果有一个非静态内部类对象那么一定存在对应的外部类对象。非静态内部类对象单独属于外部类的某个对象。

ii. 非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类成员。

iii. 非静态内部类不能有静态方法、静态属性和静态初始化块。

iv. 外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量、创建实例。

v. 成员变量访问要点:

  1. 内部类里方法的局部变量:变量名。

  2. 内部类属性:this.变量名。

  3. 外部类属性:外部类名.this.变量名。

【示例5-20】成员变量的访问要点

class Outer {
    private int age = 10;
    class Inner {
        int age = 20;
        public void show() {
            int age = 30;
            System.out.println("内部类方法里的局部变量age:" + age);// 30
            System.out.println("内部类的成员变量age:" + this.age);// 20
            System.out.println("外部类的成员变量age:" + Outer.this.age);// 10
        }
    }
}

vi. 内部类的访问:

  1. 外部类中定义内部类:
    new Inner()
  2. 外部类以外的地方使用非静态内部类:
    Outer.Inner varname = new Outer().new Inner()。

【示例5-21】内部类的访问

public class TestInnerClass {
    public static void main(String[] args) {
        //先创建外部类实例,然后使用该外部类实例创建内部类实例
        Outer.Inner inner = new Outer().new Inner();
        inner.show();
        Outer outer = new Outer();
        Outer.Inner inn = outer.new Inner();
        inn.show();
    }
}

在这里插入图片描述
b) 静态内部类
i. 定义方式:
static class ClassName {
//类体
}
ii. 使用要点:

  1. 当一个静态内部类对象存在,并不一定存在对应的外部类对象。 因此,静态内部类的实例方法不能直接访问外部类的实例方法。
  2. 静态内部类看做外部类的一个静态成员。 因此,外部类的方法中可以通过:“静态内部类.名字”的方式访问静态内部类的静态成员,通过 new 静态内部类()访问静态内部类的实例。

【示例5-22】静态内部类的访问

class Outer{
    //相当于外部类的一个静态成员
    static class Inner{
    }
}
public class TestStaticInnerClass {
    public static void main(String[] args) {
        //通过 new 外部类名.内部类名() 来创建内部类对象
        Outer.Inner inner =new Outer.Inner();
    }
}

匿名内部类
适合那种只需要使用一次的类。比如:键盘监听操作等等。

语法:
new 父类构造器(实参类表) \实现接口 () {
//匿名内部类类体!
}

【示例5-23】匿名内部类的使用

this.addWindowListener(new WindowAdapter(){
        @Override
        public void windowClosing(WindowEvent e) {
            System.exit(0);
        }
    }
);
this.addKeyListener(new KeyAdapter(){
        @Override
        public void keyPressed(KeyEvent e) {
            myTank.keyPressed(e);
        }      
        @Override
        public void keyReleased(KeyEvent e) {
            myTank.keyReleased(e);
        }
    }
);

注意

  1. 匿名内部类没有访问修饰符。

  2. 匿名内部类没有构造方法。因为它连名字都没有那又何来构造方法呢。

局部内部类
还有一种内部类,它是定义在方法内部的,作用域只限于本方法,称为局部内部类。

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

局部内部类在实际开发中应用很少。

【示例5-24】方法中的内部类

public class Test2 {
    public void show() {
        //作用域仅限于该方法
        class Inner {
            public void fun() {
                System.out.println("helloworld");
            }
        }
        new Inner().fun();
    }
    public static void main(String[] args) {
        new Test2().show();
    }
}

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值