day09_JAVAOOP(四)

本文详细介绍了Java中的内部类,包括成员内部类、局部内部类和匿名内部类的定义、使用和优缺点。此外,还讨论了引用类型作为方法参数和返回值的情况,以及final关键字的作用和使用。同时,讲解了包的定义、规范和类之间的访问控制,以及static关键字的特性,如静态变量和静态方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

内部类

什么是内部类

将一个类定义在另一个类里面,里面那个称之为内部类,外面那个称之为外部类

内部类的分类

  • 成员内部类
  • 局部内部类
  • 匿名内部类

成员内部类

成员内部类格式

class 外部类{
    class 内部类{
    }
}

成员内部类访问特点

  • 内部类可以直接访问外部类的成员,包括私有成员
  • 外部类要访问内部类的成员,必须要建立内部类的对象

创建内部类对象格式

外部类名.内部类名 对象名 = new 外部类型().new 内部类型();

代码演示

  • 成员内部类演示
package cn.zhuo_01;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 9:12
 * @Desc: 成员内部类演示
 */
public class Person {
    private boolean live;

    public void setLive(boolean live) {
        this.live = live;
    }

    //成员内部类
    class Heart{
        int sum = 20;
        //成员内部类的成员方法
        public void jump(){
            //内部类可以直接访问外部类的成员,包括私有成员
            if(live){
                System.out.println("心在跳,似爱情如烈火");
            }else {
                System.out.println("GG");
            }

        }
    }

    //外部类要访问内部类的成员,必须要建立内部类的对象
    public void show() {
        Heart he = new Heart();
        System.out.println(he.sum);
    }
}

  • 测试类
package cn.zhuo_01;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 9:17
 * @Desc: 成员内部类测试
 */
public class Tset {

    public static void main(String[] args) {

        //创建外部类对象
        Person person = new Person();
        person.setLive(true);
        person.show();

        //创建内部类对象
        //Person.Heart ph = new Person().new Heart();这里拿不到上面给live的true
        //因为这里创建了新的new person() 跟上面的new person()不一样,自然拿不到上面给Person类成员变量的true

        Person.Heart ph = person.new Heart();
        ph.jump();

    }
    
}

  • :内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但前面冠以外部类的类名和$符号,如:Person$Heart.class

局部内部类

局部内部类:将一个类定义在一个方法中,该类称之为局部内部类

如何使用局部内部类

只能在该方法内部使用局部内部类(方法与方法之间是有隔离的)

代码演示

package cn.zhuo_02;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 9:24
 * @Desc: 局部内部类演示
 */
public class Outer {

    //成员变量
    int sum = 20;

    //成员方法
    public void show(){

        //局部变量
        int num = 10;

        //局部内部类
        class Inner{
            //局部内部类的成员方法
            public void method(){
                System.out.println("你在笑,说疯狂的人是我");
                //可以访问到局部变量和成员变量
                System.out.println(num);
                System.out.println(sum);
            }
        }

        //只能在成员方法中调用
        Inner inner = new Inner();
        inner.method();

        new Inner().method();//同上
    }
}

  • 测试类
package cn.zhuo_02;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 9:27
 * @Desc: 局部内部类测试
 */
public class Test {

    public static void main(String[] args) {

        Outer outer = new Outer();
        outer.show();
    }
}

匿名内部类

匿名内部类是内部类的简化写法,本质是一个 带具体实现的 父类或者父接口的 匿名的 子类对象

使用匿名内部类的前提

匿名内部类必须继承一个父类或者实现一个接口

匿名内部类的格式

new 父类名或者接口名(){
    @Override//方法重写
    public void method(){
        //执行语句
    }
};

匿名内部类的使用

以接口为例,三种使用方式

  • 接口
package cn.zhuo_03;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 9:33
 * @Desc:
 */
public interface FlyAble {
    void fly();
    void show();
}

  • 测试类
package cn.zhuo_03;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 9:34
 * @Desc:
 */
public class Test {
    public static void main(String[] args) {
        //原版:通过定义接口的实现类来实例化接口并调用功能
        FlyAble flyAble = new FlyAbleImpl();
        flyAble.fly();*/

        //匿名内部类使用方法一:一次只能调用一个方法
        new FlyAble(){
            @Override
            public void show() {
                System.out.println("我看见爱的火焰闪烁");
            }

            @Override
            public void fly() {
                System.out.println("爱如火会温暖了心窝");
            }
        }.show();

        //使用方法二:需要调用多个方法时,调用比较简单
        FlyAble flyAble = new FlyAble(){
            @Override
            public void fly() {
                System.out.println("爱如火会温暖了心窝");
            }

            @Override
            public void show() {
                System.out.println("我看见爱的火焰闪烁");

            }
        };
        flyAble.fly();
        flyAble.show();


        //使用方法三:
        showFly(new FlyAble() {
            @Override
            public void fly() {
                System.out.println("爱如火会温暖了心窝");
            }
            @Override
            public void show() {
                System.out.println("我看见爱的火焰闪烁");
            }
        });
    }
    public static void showFly(FlyAble f){
        f.fly();
        f.show();
    }
}

匿名内部类的好处

就是可以不用再写一个实现类来实现接口,可直接使用

引用类型方法的参数和返回值

普通类—作为方法的参数及返回值

普通类—作为方法的形参

  • 方法的形参是类名,其实需要的是该类的对象
  • 实际传递的是该对象的地址值

普通类—作为方法的返回值

  • 方法的返回值类型是类名,其实返回的是该类的对象
  • 实际传递的是该对象的地址值

代码演示

  • 第一个类
package cn.zhuo_04;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 10:19
 * @Desc: 普通类-作为方法的形参 和返回值
 */
public class Student {

    public void study(){
        System.out.println("试着留盏灯假装陪伴失眠的我");
    }

    public void show(){
        System.out.println("窗口就有等待的效果");
    }
}

  • 第二个类
package cn.zhuo_04;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 10:19
 * @Desc: 普通类-作为方法的形参 和返回值
 */
public class StudentDemo {

    //成员方法,把普通类当成一个参数
    public void method(Student student){
        student.study();
    }

    //返回值类型为一个类
    public Student getStudent(){
        //方法的返回值是类名,其实返回的是该类的对象
        /*Student student = new Student();
        return  student;*/
        return new Student();
    }
}

  • 测试类
package cn.zhuo_04;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 10:20
 * @Desc: 普通类-作为方法的形参和返回值
 */
public class Test {
    public static void main(String[] args) {

        //创建对象
        StudentDemo st = new StudentDemo();

        Student s = new Student();

        //方法的形参是类名,其实需要的是该类的对象
        st.method(s);

        //返回也是一个对象
        Student student = st.getStudent();
        student.show();
    }
}

抽象类—作为方法的参数及返回值

抽象类—作为形参和返回值

  • 方法的形参是抽象类名,其实需要的是该抽象类的子类对象
  • 方法的返回值是抽象类名,其实返回的是该抽象类的子类对象

代码演示

  • 抽象类
package cn.zhuo_05;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 11:48
 * @Desc: 抽象类作为形参 和返回值
 */
public abstract class Person {
    //抽象类的成员方法
    public abstract void study();
    public abstract void show();
}

  • 抽象类的子类
package cn.zhuo_05;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 12:00
 * @Desc: 抽象类作为形参 和返回值
 */
public class Student extends Person{
    @Override
    public void study() {
        System.out.println("已经习惯摆放好两人份的餐桌");
    }

    @Override
    public void show() {
        System.out.println("这样看上去就不寂寞");
    }
}

  • Demo类
package cn.zhuo_05;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 11:48
 * @Desc: 抽象类作为形参 和返回值
 */
public class PersonDemo {

    //抽象类作为形参
    public void method(Person p){
        p.study();
    }

    //返回对象是一个抽象类
    public Person getPerson() {
        //person是一个抽象类,只能通过多态的方法实例化
        /*Person p = new Student();
        return p;*/
        return new Student();
    }
}

  • 测试类
package cn.zhuo_05;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 11:48
 * @Desc: 抽象类作为形参 和返回值
 */
public class PersonTest {
    public static void main(String[] args) {

        PersonDemo pd = new PersonDemo();

        //抽象类需要一个具体类来实现
        //抽象类作为参数,必须实例化
        Person p = new Student();//method的参数是一个抽象类,将抽象类以多态的方式实例化

        pd.method(p);

        //返回的是 new student(),相当于 Person person = new Student();
        Person person = pd.getPerson();
        person.show();
    }
}

接口类—作为方法的参数及返回值

接口作为形参和返回值

  • 方法的形参是接口名,其实需要的是该接口的实现类对象
  • 方法的返回值是接口名,其实返回的是该接口的实现类对象

代码演示

  • 接口
package cn.zhuo_06;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 11:47
 * @Desc: 接口类-作为方法的参数及返回值
 */
public interface Love {
    public abstract void show();
    public abstract void show1();
}

  • 接口的实现类
package cn.zhuo_06;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 12:11
 * @Desc: 接口类-作为方法的参数及返回值
 */
public class LoveImpl implements Love{

    @Override
    public void show() {
        System.out.println("那是你离开了北京的生活");
    }

    @Override
    public void show1() {
        System.out.println("街上的人偶尔会模仿你小动作");
    }
}

  • Demo类
package cn.zhuo_06;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 11:47
 * @Desc: 接口类-作为方法的参数及返回值
 */
public class LoveDemo {

    //接口作为参数
    public void method(Love love){
        love.show();
    }

    //接口作为返回值
    public Love getLove(){

        // 接口不能直接返回,需要实例化,多态的方式
        // Love love = new LoveImpl();
        // return love;

        return new LoveImpl();
    }

}

  • 测试类
package cn.zhuo_06;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 11:47
 * @Desc: 接口类-作为方法的参数及返回值
 */
public class LoveTest {
    public static void main(String[] args) {

        LoveDemo ld = new LoveDemo();

        //需要对接口的参数进行实现化,多态的方法
        Love love = new LoveImpl();
        //参数需要的是一个接口
        ld.method(love);
        //或 ld.method(new LoveImpl());

        Love ldLove = ld.getLove();
        ldLove.show1();


    }
}

final关键字

概述

为了避免出现随意改写的情况,Java提供了final关键字,用于修饰不可改变的内容

特点

final表示不可改变,可用于修饰类、方法和变量

  • 类:被修饰的类,不可被继承
  • 方法:被修饰的方法,不可被重写
  • 变量:被修饰的变量,不能重新赋值,变成了常量

final的使用

  1. 修饰类
    • 格式:
public final class Fu{}
//public class Zi extends Fu{}——错误
//子类不能继承final所修饰的父类
  1. 修饰方法
  2. 修饰变量
  3. 代码演示:
package cn.zhuo_07;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 14:43
 * @Desc:
 */
//被 final 修饰的类,不能被继承。
//public final class Fu {
public class Fu{

    final int num = 10;

    public final void show(){

        System.out.println("不能被重写");

    }
}

package cn.zhuo_07;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 14:44
 * @Desc:
 */
public class Son extends Fu{

    //public void show() {} //show方法不能被重写

}

package cn.zhuo_07;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 14:49
 * @Desc:
 */
public class Test {

    public static void main(String[] args) {
        Fu fu = new Fu();
        //被 final修饰的变量,不能被重新赋值,变成了常量
        //fu.num = 20;
        fu.show();
    }
}

包的定义及规范

包的定义

  1. 使用package定义包
  2. 格式:package 包名;(如果是多级包,中间用.隔开)

注意事项

  1. package语句必是程序的第一条可执行代码
  2. 一个Java文件中只能有一个package语句
  3. 若无package默认表示无包名

类与类之间的访问

  1. 同一个包下:无需导包,直接访问
  2. 不同包下:inport导包后访问;全类名(包名+类名)访问

注:

package必须是程序的第一条可执行代码

import需要写在package下面

class需要写在import下面

分包

  • 功能分包
  • 模块分包
  • 业务模块分层包

权限修饰符

权限概述

  1. public:公共的
  2. protected:受保护的
  3. default:默认的
  4. private:私有的

不同情况下的不同权限访问情况

代码略,敲好了,懒得复制过来了

总结

  1. 四大权限中public为最大的权限,private为最小权限
    • 所有子类都可以访问父类中protected修饰的成员
    • 同一个包下的类都可以访问default修饰的成员
  2. 建议:
    • 成员变量:private—隐藏细节
    • 成员方法:public—方便调用
    • 构造方法:public—方便创造对象

static关键字

可用来修饰成员变量和成员方法,被修饰的成员是属于类的,而不单是属于某个对象的,也就是说,可以不靠创造对象来调用

static的特点

  1. 可修饰成员变量、成员方法
  2. 随着类的加载而加载
  3. 优先于对象存在
  4. 被类的所有对象共享
  5. 可通过类名调用

静态变量

详见代码

静态方法

详见代码

package cn.zhuo_09;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 16:01
 * @Desc: 静态变量和静态方法
 */
public class Student {

    //非静态变量(动态变量)
    int num1 = 10;

    //静态变量
    static int num2 = 20;

    //非静态方法
    public void show(){
        System.out.println(num1);
        System.out.println(this.num1);
        System.out.println(num2);

        //非静态方法可以访问静态方法也可以访问非静态方法
        function();
        function2();
    }

    //静态方法
    public static void method(){

        //静态不能访问非静态的成员变量
        //System.out.println(num1);

        //静态中没有 this
        //System.out.println(this.num1);

        //静态方法可以访问静态的成员变量
        System.out.println(num2);

        //静态方法不能访问非静态方法
        //function();

        //静态方法可以访问静态方法
        function2();
    }
    public void function(){
        System.out.println("轻而易举就能将我击破");
    }

    public static void function2(){
        System.out.println("那些承诺提起人是你,还是我");
    }
}

package cn.zhuo_09;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 16:02
 * @Desc:
 */
public class StudentDemo {
    public static void main(String[] args) {
        Student student = new Student();
        System.out.println(student.num1);
        //System.out.println(student.num2);//不推荐以此方法访问静态变量

        System.out.println(Student.num2);//静态变量,可以通过:类名.变量名 的格式访问

        student.show();
        Student.method();
    }
}

static注意事项

  1. 静态方法中不能出现this关键字
  2. 静态只能访问静态,非静态可以访问静态也可以访问非静态

调用格式

static修饰的成员可以并且建议通过类名访问

  • 格式:
类名.变量名;//访问类变量
类名.静态方法名(参数);//调用静态方法

静态变量和成员变量的区别

  1. 所属不同

    • 静态变量属于类,所以也称为类变量
    • 成员变量属于对象,所以也称之为实例变量(对象变量)
  2. 内存中位置不同

    • 静态变量存储于方法区的静态区
    • 成员变量存储于堆内存中
  3. 生命周期不同

    • 静态变量随着类的加载而加载,随着类的消失而消失

    • 成员变量随着对象的创建而创建,随着对象的消失而消失

  4. 调用不同

    • 静态变量可以通过类名调用,也可以通过对象来调用
    • 成员变量只能通过对象名调用

main方法是静态的

静态代码块

定义在成员位置,使用static修饰的代码块{ }

  1. 位置:类中方法外
  2. 执行:随着类的加载而执行且仅执行一次,优先于main方法和构造方法的执行
  3. 格式:
public class ClassName{ 
   static {
       // 执行语句 
   }
}
//构造代码块
{

}
  1. 代码演示:
package cn.zhuo_10;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 20:20
 * @Desc: 静态代码块相关
 */
public class Game {

    static  int age;
    static  String name;
    //构造代码块
    {
        age = 20;
        name = "张三";
        System.out.println("那是你离开了北京的生活");
    }

    //静态代码块:随着类的加载而加载,并且只加载一次
    static {
        age = 25;
        name = "李四";
        System.out.println("我以为我爱了 就会留下些什么 纪念那些曲折");
    }

    public static void show() {
        System.out.println("我们快乐的争吵的不舍的分分合合");
    }
}

package cn.zhuo_10;

/**
 * @Auther: 不学无墅
 * @Date: 2023/7/17 20:20
 * @Desc:
 */
public class GameTest {
    //静态代码块 --> 构造代码块 --> 静态方法
    public static void main(String[] args) {
        //静态代码块 在 构造代码块 之前执行
        //静态代码块属于类,优先于对象存在
        Game g = new Game();
        //静态代码块随着类的加载而加载,并且只加载一次
        //静态代码块会执行,只执行一次
        //构造方法每一次实例化对象都会执行
        Game g2 = new Game();

        //静态方法,不调用不执行
        Game.show();
        Game.show();
    }
}

**注:**静态代码块的主要作用是给类变量进行初始化赋值

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

找不到工作当个咸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值