【Java】面向对象笔记(下)

news2024/12/23 14:05:28

9Gpdc0l3yAIYn0LrW36F

static关键字

static 静态

什么是静态

主要意义是在于创建独立于具体对象的域变量或者方法。以致于即使没有创建对象,也能使用属性和调用方法

static关键字还有一个比较关键的作用就是用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。

怎么使用static

static可以用来修饰:属性、方法、代码块、内部类

使用static修饰属性:静态变量(或类变量)

  1. 属性,按是否使用static修饰,又分为:静态属性 vs 非静态属性(实例变量)

    • 实例变量:我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。

    • 静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的。

静态变量说明

  1. 静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用

  2. 静态变量的加载要早于对象的创建。

  3. 由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中。

  4. 不能通过类直接调用对象中的实例变量,因为这时候对象还没有生成。

谁来调用\调用谁类变量实例变量
yesno
对象yesyes

内存解析

静态属性内存解析

静态方法说明

在静态的方法内,不能使用this关键字、super关键字

静态方法随着类的加载而加载,可以通过类.静态方法的方式进行调用

静态方法中,只能调用静态的方法或属性,非静态(即对象的)方法无法调用。

比如:Chinese.eat();在静态方法中调用Chinese类的非静态方法eat()是无法通过编译的

谁来调用\调用谁静态方法非静态方法
类.方法yesno
对象.方法yesyes

非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性

package com.hengxing.test;

public class StaticTest {
    public static void main(String[] args) {
        Chinese.walk();//类调用静态方法
        // Chinese.eat();//不能调用非静态方法

        //对象调用
        Chinese ch = new Chinese();
        ch.walk();
        ch.eat();
    }
}

class Chinese{
    public static void walk(){
        System.out.println("I am walking....");
    }
    public void eat() {
        System.out.println("I am eating.....");
    }
}

结果:

I am walking....
I am walking....
I am eating.....

关于静态属性和静态方法的使用,要从生命周期的角度去理解。

什么时候用static

开发中,如何确定一个属性是否要声明为static的?

  • 属性是可以被多个对象所共享的,不会随着对象的不同而不同的。

  • 类中的常量也常常声明为static

开发中,如何确定一个方法是否要声明为static的?

  • 操作静态属性的方法,通常设置为static的
  • 工具类中的方法,习惯上声明为static的。 比如:Math、Arrays、Collections

练习

  1. 圆的练习
package com.hengxing.test;

public class CircleTest {
    public static void main(String[] args) {
        Circle c1 = new Circle();
        Circle c2 = new Circle();
        Circle c3 = new Circle(3.45);

        System.out.println("c1 id is:" + c1.getId());
        System.out.println("c2 id is:" + c2.getId());
        System.out.println("c3 id is:" + c3.getId());
        System.out.println("c3 area is:" + c3.findArea());
        System.out.println("number of circle:" + Circle.getTotal());
    }
}

class Circle {

    private static int total;//统计对象圆的个数
    private static int init = 1001;//初始值
    private double radius;
    private int id;//自动赋值
    public Circle() {
        id = init++;
        total++;
    }
    public Circle(double radius) {
        this();
        this.radius = radius;
    }

    //计算面积
    public double findArea() {
        return Math.PI * radius * radius;
    }

    //getters
    public static int getTotal() {
        return total;
    }
    public static int getInit() {
        return init;
    }
    public double getRadius() {
        return radius;
    }
    public int getId() {
        return id;
    }
}
  1. 编写一个类实现银行账户的概念,包含的属性有“帐号”、“密码”、“存款余额”、“利率”、“最小余额”,定义封装这些属性的方法。账号要自动生成。编写主类,使用银行账户类,输入、输出3个储户的上述信息。

    考虑:哪些属性可以设计成static属性。

    public class Account {
        private int id;
        private int password;
        private double balance;//存款余额
        private static double interestRate;//利率
        private static double minMoney;//最小余额
        private static int init = 1000;//自动生成的初始值
    
        public Account() {
            id = init++;
            minMoney = 10;
        }
    
        public Account(int password, double balance) {
            this();
            this.password = password;
            this.balance = balance;
        }
    
        public int getId() {
            return id;
        }
        public int getPassword() {
            return password;
        }
        public void setPassword(int password) {
            this.password = password;
        }
        public double getBalance() {
            return balance;
        }
        public void setBalance(double balance) {
            this.balance = balance;
        }
        public static double getInterestRate() {
            return interestRate;
        }
        public static void setInterestRate(double interestRate) {
            Account.interestRate = interestRate;
        }
        public static double getMinMoney() {
            return minMoney;
        }
        public static void setMinMoney(double minMoney) {
            Account.minMoney = minMoney;
        }
    
        @Override
        public String toString() {
            return "Account [id=" + id + ", password=" + password + ", balance=" + balance + "]";
        }
    }
    

单例模式(Singleton)

Point : 必须掌握,当前阶段要能够手写饿汉式

为什么需要单例模式

由于单例模式只生成一个实例, 减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。

应用场景:

  • 网站的计数器,一般也是单例模式实现,否则难以同步。

  • 应用程序的日志应用,一般都使用单例模式实现,这一般是由于共享的日志
    文件一直处于打开状态,因为只能有一个实例去操作, 否则内容不好追加。

  • 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库
    资源。

  • 项目中, 读取配置文件的类,一般也只有一个对象。没有必要每次使用配置文件数据,都生成一个对象去读取。

  • Application 也是单例的典型应用

  • Windows的Task Manager (任务管理器)就是很典型的单例模式

  • Windows的Recycle Bin (回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。

饿汉式实现

package com.hengxing.test;

public class SingletonTest {
    public static void main(String[] args) {
        Bank bank1 = Bank.getInstance();//只能通过公共方法来获取实例
        Bank bank2 = Bank.getInstance();
        System.out.println(bank1 == bank2);//true
    }
}

class Bank{

    //1.私有化构造方法
    private Bank(){}
    
    //2.类内部生成私有对象
    //4.静态化对象
    private static Bank bank = new Bank();
    

    //3.公共方法返回对象,要想在静态方法中调用,必须是静态的
    public static Bank getInstance(){
        return bank;
    }
}

懒汉式实现

目前阶段的实现还有待优化。请看二者对比

package com.hengxing.test;

public class SingletonTest {
    public static void main(String[] args) {
        Bank bank1 = Bank.getInstance();//只能通过公共方法来获取实例
        Bank bank2 = Bank.getInstance();
        System.out.println(bank1 == bank2);//true
    }
}

class Bank{

    //1.私有化构造方法
    private Bank(){}
    
    //2.类内部生成私有对象
    //4.静态化对象
    private static Bank bank = null;

    //3.公共方法返回对象,要想在静态方法中调用,必须是静态的
    public static Bank getInstance(){
        if (bank == null) {
            bank = new Bank();
        }
        return bank;
    }
}

二者的对比

饿汉式

坏处:对象加载时间过长

好处:线程安全

懒汉式(目前的写法)

好处:延迟对象创建

坏处:线程不安全,若两个线程同时在if判断中,且instance为空,会创建两个对象。—>到 多线程 内容时再修改

Main方法

main()方法的使用说明:

  1. main()方法作为程序的入口

  2. main()方法也是一个普通的静态方法

  3. main()方法可以作为我们与控制台交互的方式。(之前:使用Scanner)

方法块(初始化块)

代码块的作用

用来初始化类

代码块如果有修饰的话,只能使用static.

分类:静态代码块 vs 非静态代码块

静态代码块

内部可以有输出语句

  • 随着类的加载而执行,而且只执行一次
  • 作用:初始化类的信息
  • 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
  • 静态代码块的执行要优先于非静态代码块的执行
  • 静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构

非静态代码块

内部可以有输出语句

  • 随着对象的创建而执行
  • 每创建一个对象,就执行一次非静态代码块
  • 作用:可以在创建对象时,对对象的属性等进行初始化
  • 如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
  • 非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法

回顾属性赋值的位置

按初始化顺序排列

  1. 默认初始化

  2. 显示初始化

    在代码块中赋值(此两部分按编写时先后顺序排列)

  3. 构造器中初始化

  4. 有对象后,用Object.fieldObject.method()等方式赋值

final关键字

final:最终的

final可以用来修饰的结构:类、方法、变量

  1. final 用来修饰一个类:此类不能被其他类所继承。

    比如:String类、System类、StringBuffer类

  2. final 用来修饰方法:表明此方法不可以被重写

    比如:Object类中getClass();

  3. final 用来修饰变量:此时的"变量"就称为是一个常量

  • final 修饰属性:

可以考虑赋值的位置有:显式初始化、代码块中初始化、构造器中初始化

  • final 修饰局部变量:

尤其是使用final 修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。

一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。

static final 用来修饰属性:全局常量

abstract关键字

abstract 抽象的

abstract 可以用来修饰的结构:类、方法

abstract修饰类:抽象类

此类不能实例化

抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程)

开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作

abstract修饰方法:抽象方法

抽象方法只有方法的声明,没有方法体

包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。

若子类重写了父类中的所有的抽象方法后,此子类方可实例化

若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰

注意点

abstract使用上的注意点:

  1. abstract不能用来修饰:属性、构造器等结构

  2. abstract不能用来修饰私有方法、静态方法、final的方法、final的类

抽象类的匿名子类

先来回顾一下匿名对象

public static void main(String[] args) {
    method(new Manager());//不起名了,直接丢进去
    //输出:Manager is working!
}

public static void method(Employee e){
    e.work();
}
//Manager类中重写了work()方法

将其称之为非匿名类的匿名对象,非匿名类指通过Manager类创建对象

我们更进一步,把类名也匿名了,在创建对象时,直接使用抽象的父类代替,然后把需要重写的方法重写之后,放进形参中

public static void main(String[] args) {
    method(new Employee() {
        @Override
        public void work() {
            System.out.println("临时工来工作啦!!!");
        }
    });
}

public static void method(Employee e){
    e.work();//临时工来工作啦!!!
}

这就是匿名类的匿名对象

模板方法的设计模式

public class TemplateTest {
	public static void main(String[] args) {
		SubTemplate t = new SubTemplate();
		t.spendTime();
	}
}

abstract class Template{
	//计算某段代码执行所需要花费的时间
	public void spendTime(){
		
		long start = System.currentTimeMillis();
		this.code();//不确定的部分、易变的部分
		long end = System.currentTimeMillis();
		System.out.println("花费的时间为:" + (end - start));
		
	}
	
	public abstract void code();	
}

实例参考:

//抽象类的应用:模板方法的设计模式
public class TemplateMethodTest {

	public static void main(String[] args) {
		BankTemplateMethod btm = new DrawMoney();//需要取钱就用取钱类
		btm.process();

		BankTemplateMethod btm2 = new ManageMoney();//需要理财就用理财类
		btm2.process();
	}
}
abstract class BankTemplateMethod {
	// 具体方法
	public void takeNumber() {
		System.out.println("取号排队");
	}

	public abstract void transact(); // 办理具体的业务 //钩子方法

	public void evaluate() {
		System.out.println("反馈评分");
	}

	// 模板方法,把基本操作组合到一起,子类一般不能重写
	public final void process() {
		this.takeNumber();

		this.transact();// 像个钩子,具体执行时,挂哪个子类,就执行哪个子类的实现代码

		this.evaluate();
	}
}

class DrawMoney extends BankTemplateMethod {
	public void transact() {
		System.out.println("我要取款!!!");
	}
}

class ManageMoney extends BankTemplateMethod {
	public void transact() {
		System.out.println("我要理财!我这里有2000万美元!!");
	}
}

项目练习

编写工资系统, 实现不同类型员工(多态)的按月发放工资。 如果当月出现某个
Employee对象的生日, 则将该雇员的工资增加100元。
实验说明:

  1. 定义一个Employee类,该类包含:
    private成员变量name,number,birthday,其中birthday 为MyDate类的对象;
    abstract方法earnings();
    toString()方法输出对象的name,number和birthday。

  2. MyDate类包含:
    private成员变量year,month,day ;
    toDateString()方法返回日期对应的字符串: xxxx年xx月xx日

  3. 定义SalariedEmployee类继承Employee类,实现按月计算工资的员工处
    理。该类包括: private成员变量monthlySalary;
    实现父类的抽象方法earnings(),该方法返回monthlySalary值; toString()方法输
    出员工类型信息及员工的name, number,birthday。

  4. 参照SalariedEmployee类定义HourlyEmployee类,实现按小时计算工资的
    员工处理。该类包括:
    private成员变量wage和hour;
    实现父类的抽象方法earnings(),该方法返回wage*hour值;
    toString()方法输出员工类型信息及员工的name, number,birthday。

  5. 定义PayrollSystem类,创建Employee变量数组并初始化,该数组存放各
    类雇员对象的引用。利用循环结构遍历数组元素,输出各个对象的类
    型,name,number,birthday,以及该对象生日。当键盘输入本月月份值时,如果本
    月是某个Employee对象的生日,还要输出增加工资信息。

提示:

//定义People类型的数组People c1[]=new People[10];

//数组元素赋值
c1[0]=new People(“John”,“0001”,20);
c1[1]=new People(“Bob”,“0002”,19);
//若People有两个子类Student和Officer, 则数组元素赋值时, 可以使父类类型的数组元素指向子类。
c1[0]=new Student(“John”,“0001”,20,85.0);
c1[1]=new Officer(“Bob”,“0002”,19,90.5);

实现:

public abstract class Employee {
    private String name;
    private int number;
    private MyDate birthday;

    
    public Employee() {}

    public Employee(String name, int number, MyDate birthday) {
        this.name = name;
        this.number = number;
        this.birthday = birthday;
    }

    public abstract double earnings();

    @Override
    public String toString() {
        return "name=" + name + ", number=" + number + ", birthday=" + birthday.toDateString();
    }

    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    public int getNumber() {return number;}
    public void setNumber(int number) {this.number = number;}
	public MyDate getBirthday() {return birthday;}
    public void setBirthday(MyDate birthday) {
        this.birthday = birthday;
    }
}
public class MyDate {
    private int year;
    private int month;
    private int day;
    
    
    public MyDate() {
    }

    public MyDate(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public String toDateString(){
        return year + "年" + month + "月" + day + "日";
    }
    public int getYear() {return year;}
    public void setYear(int year) {this.year = year;}
    public int getMonth() {return month;}
    public void setMonth(int month) {this.month = month;}
    public int getDay() {return day;}
    public void setDay(int day) {this.day = day;}
}
public class HourlyEmployee extends Employee {
    private double wage;
    private int hour;
    
    public HourlyEmployee() {}
    public HourlyEmployee(double wage, int hour) {
        this.wage = wage;
        this.hour = hour;
    }
    public HourlyEmployee(String name, int number, MyDate birthday, double wage, int hour) {
        super(name, number, birthday);
        this.wage = wage;
        this.hour = hour;
    }
    
    @Override
    public double earnings() {
        return wage * hour;
    }
    @Override
    public String toString() {
        return "HourlyEmployee [" + super.toString() + ", wage=" + wage + ", hour=" + hour + "]";
    }
}
public class SalariedEmployee extends Employee {
    private double monthlySalary;
    
    public SalariedEmployee() {}
    public SalariedEmployee(String name, int number, MyDate birthday, double monthlySalary) {
        super(name, number, birthday);
        this.monthlySalary = monthlySalary;
    }

    @Override
    public double earnings() {
        return monthlySalary;
    }

    @Override
    public String toString() {
        return "SalariedEmployee [" + super.toString() + ", monthlySalary=" + monthlySalary + "]";
    }    
}
import java.util.Calendar;
import java.util.Scanner;

public class PayrollSystem {
    public static void main(String[] args) {
        Employee[] emps = new Employee[4];
        emps[0] = new HourlyEmployee("Cloud",19,new MyDate(2000,10,26),50,240);
        emps[1] = new HourlyEmployee("Tifa",17,new MyDate(2003,06,16),60,240);
        emps[2] = new SalariedEmployee("Arith",19,new MyDate(2003,12,8),3000);
        emps[3] = new SalariedEmployee("Barit",30,new MyDate(1987,01,23),2000);

        //方式一:手动获取
        // Scanner scan = new Scanner(System.in);
        // int month = scan.nextInt();
        //方式二:自动提取
        Calendar calendar = Calendar.getInstance();
        int month = calendar.get(calendar.MONTH) + 1;
        for (int i = 0; i < emps.length; i++) {
            if (month == emps[i].getBirthday().getMonth()) {
                System.out.println("今天是" + emps[i].getName() +"的生日,工资加倍!");
                System.out.println(emps[i].toString());
                System.out.println("月工资为:" + (emps[i].earnings() + 100));
            }else {
                System.out.println(emps[i].toString());
                System.out.println("月工资为:" + emps[i].earnings());
            }
        }
    }
}

接口interface

什么是接口

抽象类是从多个类中抽象出来的模板,如果将这种抽象进行的更彻底,则可以提炼出一种更加特殊的“抽象类”——接口(Interface)。接口是Java中最重要的概念之一,它可以被理解为一种特殊的类,不同的是接口的成员没有执行体,是由全局常量和公共的抽象方法所组成。

为什么需要接口

一方面, 有时必须从几个类中派生出一个子类, 继承它们所有的属性和方法。 但是, Java不支持多重继承。 有了接口, 就可以得到多重继承的效果。

接口举例

另一方面, 有时必须从几个类中抽取出一些共同的行为特征,而它们之间又没有is-a的关系,仅仅是具有相同的行为特征而已。例如:鼠标、键盘、打印机、扫描仪、摄像头、充电器、 MP3机、手机、数码相机、移动硬盘等都支持USB连接。

接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要…则必须能…”的思想。 继承是一个"是不是"的关系,而接口实现则是 "能不能"的关系。

接口的本质是契约,标准,规范,就像我们的法律一样。制定好后大家都要遵守。

怎么使用接口

  1. 接口使用interface来定义

  2. Java中,接口和类是并列的两个结构

  3. 如何定义接口:定义接口中的成员

    • JDK7及以前:只能定义全局常量和抽象方法

      全局常量:public static final的.但是书写时,可以省略不写

      抽象方法:public abstract的

    • JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法(略)

  4. 接口中不能定义构造器!意味着接口不可以实例化

  5. Java开发中,接口通过让类去实现implements的方式来使用。

    如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化

    如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类

  6. Java类可以实现多个接口 —>弥补了Java单继承性的局限性

    格式:class AA extends BB implements CC,DD,EE

接口的匿名

  1. 接口使用上也满足多态性

  2. 接口,实际上就是定义了一种规范

在开发中,体会面向接口编程!

public static void main(String[] args) {
    Computer com = new Computer();
    //1.创建了接口的非匿名实现类的非匿名对象
    Flash flash = new Flash();
    com.transferData(flash);

    //2. 创建了接口的非匿名实现类的匿名对象
    com.transferData(new Printer());

    //3. 创建了接口的匿名实现类的非匿名对象
    USB phone = new USB(){
        @Override
        public void start() {
            System.out.println("手机开始工作");
        }
        @Override
        public void stop() {
            System.out.println("手机结束工作");
        }
    };
    com.transferData(phone);


    //4. 创建了接口的匿名实现类的匿名对象
    com.transferData(new USB(){
        @Override
        public void start() {
            System.out.println("mp3开始工作");
        }

        @Override
        public void stop() {
            System.out.println("mp3结束工作");
        }
    });
}

class Computer{
	public void transferData(USB usb){//USB usb = new Flash();
		usb.start();
		System.out.println("具体传输数据的细节");
		usb.stop();
	}
}

interface USB{
	//常量:定义了长、宽、最大最小的传输速度等
	void start();
	void stop();
}

新特性:默认方法与静态方法

JDK8中新增:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法

public interface CompareA {
	
	//静态方法
	public static void method1(){
		System.out.println("CompareA:北京");
	}
	//默认方法
	public default void method2(){
		System.out.println("CompareA:上海");
	}
	//省略权限符,但是会自动补足
	default void method3(){
		System.out.println("CompareA:上海");
	}
}

怎么使用?

public class SubClassTest {
	public static void main(String[] args) {
		SubClass s = new SubClass();
//		s.method1();
//		SubClass.method1();
		//知识点1:接口中定义的静态方法,只能通过接口来调用。
		CompareA.method1();
		//知识点2:通过实现类的对象,可以调用接口中的默认方法。
		//如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法
		s.method2();
		//知识点3:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,
		//那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。-->类优先原则
		//知识点4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,
		//那么在实现类没有重写此方法的情况下,报错。-->接口冲突。
		//这就需要我们必须在实现类中重写此方法
		s.method3();
	}
}

class SubClass extends SuperClass implements CompareA{
	
	public void method2(){
		System.out.println("SubClass:上海");
	}
	
	public void method3(){
		System.out.println("SubClass:深圳");
	}
    //知识点5:如何在子类(或实现类)的方法中调用父类、接口中被重写的方法
	public void myMethod(){
		method3();//调用自己定义的重写的方法
		super.method3();//调用的是父类中声明的
		//调用接口中的默认方法
		CompareA.super.method3();
	}
}

默认方法与静态方法让接口变得更像类了

新特性的应用

可以来看一个有趣的例子,妈妈和老婆同时掉水里,你救谁?

一个人如果同时继承孝顺的和痴情的两个接口,自己却不重写,那就会出错。

但是此时你爸爸发话了:“救你老妈!”子类继承了父类的方法,类优先,所以你听你爸的。

通过接口名.super.方法名();这种方式调用接口中的默认方法

interface Filial {// 孝顺的
	default void help() {
		System.out.println("老妈,我来救你了");
	}
}

interface Spoony {// 痴情的
	default void help() {
		System.out.println("媳妇,别怕,我来了");
	}
}

class Father{
	public void help(){
		System.out.println("儿子,救我媳妇!");
	}
}

class Man extends Father implements Filial, Spoony {
	@Override
	public void help() {
		System.out.println("我该救谁呢?");
		Filial.super.help();
		Spoony.super.help();
	}
}

内部类

什么是内部类

Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类

内部类分两种:

成员内部类(静态、非静态) vs 局部内部类(方法内、代码块内、构造器内)

为什么需要内部类

有时候我们需要描述一个类中的属性,但这个属性有点复杂,一个变量不够描述。就需要一个类作为它的属性,单独再划分一个类出去没有必要,这只是我的一个属性,别人没有。比如,人有看书这个爱好,但是其他任何类都不需要这个属性。

怎么使用内部类

回顾外部类的成员,它可以:

  • 调用外部类结构
  • 被static修饰
  • 被4种不同的权限修饰

作为一个类:

  • 类内可以定义属性、方法、构造器等
  • 被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
  • 被abstract修饰

如何在成员内部类中区分调用外部类的结构

//创建实例(静态的成员内部类):
TV tv = new Person.TV();
tv.show();
//创建非静态成员的内部类
Person person = new Person();
ball ball = person.new ball();

public void display(String name){
    System.out.println(name);//方法的形参
    System.out.println(this.name);//内部类的属性
    System.out.println(Person.this.name);//外部类的属性
}

本文参考:

Java接口(Interface)的定义和实现

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/193160.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数字授权如何满足工业软件多样化需求?

前言数字化转型的洪流正在不断对工业软件提出新的要求。在包括“智能工厂”、“智能生产”以及“智能物流”在内的主要领域里&#xff0c;工业软件正逐渐向智能化、嵌入式、分布式、互联化的方向演进。传统的软件保护和授权方式并不能适应工业软件新形式的需求。一方面&#xf…

蓝桥杯 stm32 RTC实时时钟

文章代码使用 HAL 库。 文章目录前言一、RTC 重要特性&#xff1a;二、CubeMX 创建工程。三、读取系统日期 函数。四、读取系统时间 函数。四、在 LCD 上显示 时间。总结实验效果前言 RTC (Real Time Clock)&#xff1a; 实时时钟。 RTC 模块拥有一个连续计数的 计数器&#…

mysql:有哪些索引,什么时候创建索引,什么时候不创建索引,创建索引的原则有哪些。

最近学习mysql&#xff0c;学习的索引的一些总结。 1.哪些索引 普通索引唯一性索引主键索引单列索引多列(组合、联合)索引全文索引补充&#xff1a;空间索引 小结&#xff1a;不同的存储引擎支持的索引类型也不一样 InnoDB &#xff1a;支持 B树。MyISAM &#xff1a; 支持…

基于JavaWeb的校园故障报修系统

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

Java里面为什么搞了双重检查锁,写完这篇文章终于真相大白了

双重检查锁定与延迟初始化 在 java 程序中&#xff0c;有时候可能需要推迟一些高开销的对象初始化操作&#xff0c;并且只有在使用这些对象时才进行初始化。此时程序员可能会采用延迟初始化。但要正确实现线程安全的延迟初始化需要一些技巧&#xff0c;否则很容易出现问题。比如…

城市POI数据爬取-百度地图版

1 API说明 目前百度地图的最新版为地图检索V2.0服务。详细介绍可以通过开发文档-web服务Api-地点检索V2.0获取。 在使用API前需要提前注册账号获取ak。对于免费账号&#xff1a;目前的每日访问次数是100次&#xff0c;最多可以获取2000条数据。 如不需讲解仅需要下载代码&am…

阿里软件架构师手写JDK源码,看完真的膜拜

最近有不少小伙伴在后台留言&#xff0c;说 Java 的面试越来越难了&#xff0c;尤其是技术面&#xff0c;考察得越来越细&#xff0c;越来越底层。 通过和大厂的面试官聊了一下发现&#xff0c;现在大厂特别爱考底层的一些原理&#xff0c;因为一些底层是不涉及到语言的&#x…

【Linux】进程状态的理解

&#x1f923; 爆笑教程 &#x1f449; 《看表情包学Linux》&#x1f448; 猛戳订阅 &#x1f525; &#x1f4ad; 写在前面&#xff1a;本章我们专门讲解进程的状态。我们先学习具体的 Linux 系统状态&#xff0c;再去介绍 OS 学科面对的概念如何理解 —— 运行态、终止态、阻…

二叉树的基础应用

二叉树 树概念及结构 1.1树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因 为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 有一个特殊的结点…

Seata分布式事务落地解决方案

引言上一篇文章介绍了分布式事务理论和相关解决方案的具体思路&#xff0c;我们下面快速复习一下相关知识点:1.分布式事务问题1.1.本地事务本地事务&#xff0c;也就是传统的单机事务。在传统数据库事务中&#xff0c;必须要满足四个原则&#xff1a;1.2.分布式事务分布式事务&…

Houdini_grass_sim (关于植物结算)

2023-2-2 开年第一篇 &#xff08;记录下关于植物结算的笔记&#xff09; 这是我们要算的植物&#xff08;草&#xff09; 思路 这个草分2部分 主干和叶子&#xff08;这里我没考虑取解决穿插&#xff09; 1.主干提取中心线 —— 2.用线结算器&#xff08;主干&#xff09;—…

MongoDB的安装(window系统)

最近因为用到mongodb&#xff0c;所以研究了一下&#xff0c;遇到一些问题&#xff0c;和大家分析一下。介绍&#xff1a;MongoDB 是一个基于分布式文件存储的数据库。由 C 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。MongoDB 是一个介于关系数据库和非关系…

AcWing 320. 能量项链(环形区间DP)

AcWing 320. 能量项链&#xff08;环形区间DP&#xff09;一、 问题&#xff1a;二、分析&#xff1a;三、代码一、 问题&#xff1a; 二、分析&#xff1a; 在讲解这道题之前&#xff0c;大家需要对线性区间DP和环形区间DP有一定的了解&#xff0c;因此如果不会这两个知识点的…

SpringSecurity 安全框架详解

SpringSecurity 安全框架详解 1.简介 先赘述一下身份认证和用户授权&#xff1a; 用户认证&#xff08;Authentication&#xff09;&#xff1a;系统通过校验用户提供的用户名和密码来验证该用户是否为系统中的合法主体&#xff0c;即是否可以访问该系统&#xff1b;用户授权…

【JavaEE】文件操作IO之File 、InputStream、OutputStream 用法详解

目录 一、文件概念 &#xff08;1&#xff09;文件定义与组成 &#xff08;2&#xff09;文件的树形结构组织和目录 &#xff08;3&#xff09;文件路径 &#xff08;4&#xff09;文件分类 &#xff08;5&#xff09;文件操作 二、文件操作File类 &#xff08;1&…

20230202在AIO-3568J开发板在原厂Android12下增加ll命令

20230202在AIO-3568J开发板在原厂Android12下增加ll命令 2023/2/2 11:50 1、使用EVB2的DTS&#xff1a;rk3568-evb2-lp4x-v10.dts&#xff0c;ENG模式编译。没有ll命令&#xff01; console:/ $ console:/ $ ll /system/bin/sh: ll: inaccessible or not found 127|console:/ …

ESP-IDF:堆排序测试

堆排序测试 /堆排序测试/ void printheap (int arr[],int length) { for(int i0;i<length;i) { cout<<arr[i]<<" "; } cout<<endl; } void swapheap (int arr[],int a, int b) { int temp arr[a]; arr[a] arr[b]; arr[b] temp; } void he…

【数据库原理与SQL Server应用】Part04——数据库操作

【数据库原理与SQL Server应用】Part04——数据库操作一、数据库基本概念1.1 物理数据库1.1.1 页和区1.1.2 数据库文件1.1.3 文件组1.2 逻辑数据库1.3 SQL Server 的系统数据库和用户数据库1.4 报表服务器和报表数据库二、创建数据库2.1 管理工具界面方式创建数据库2.2 命令行方…

CSS列表与表格

目录 ​编辑 HTML 列表和 CSS 列表属性 不同的列表项目标记 实例 图像作为列表项标记 实例 定位列表项标记 实例 删除默认设置 实例 列表 - 简写属性 实例 设置列表的颜色样式 实例 更多实例 所有 CSS 列表属性 表格边框 实例 全宽表格 实例 双边框 合并…

【数据结构与算法】最小生成树 | 最短路径

&#x1f320;作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《数据结构与算法要啸着学》 &#x1f387;座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;…