【day13】深入面向对象编程
【day12】回顾
在正文开始之前,先让我们回顾一下【day12】中的关键内容:
-
接口(Interface):
interface
关键字用于定义接口。implements
关键字用于实现接口。
-
接口成员:
- 抽象方法:需要在实现类中重写。
- 默认方法:可以被重写也可以不重写。
- 静态方法:可以直接通过接口名调用。
- 成员变量:通常是
public static final
的常量。
-
接口特点:
- 支持多继承。
- 支持多实现。
- 一个类可以实现多个接口。
-
多态(Polymorphism):
- 前提条件:子父类继承关系、方法重写、父类引用指向子类对象。
- 好处:扩展性强,可以使用父类类型接口传递任意子类对象。
- 弊端:不能直接调用子类特有方法。
- 转型:向上转型和向下转型。
- 成员访问特点:成员变量看等号左边是谁,成员方法看
new
的是谁。 - 转型问题:类型转换异常
ClassCastException
。 - 类型判断:
instanceof
。
模块12重点
本模块我们将深入探讨以下面向对象编程的高级主题:
final
关键字修饰成员变量的特点。- 静态代码块的使用场景和实现。
- 匿名内部类的使用。
- 权限修饰符的深入理解和应用。
第一章:权限修饰符
1. 概述
Java提供了四种访问权限修饰符,它们决定了成员的访问范围:
public
:最广的访问范围,任何地方都可以访问。protected
:在同包和子类中可以访问。- 默认(无修饰符):仅在同包内可以访问。
private
:仅在定义它的类内部可以访问。
2. 不同权限的访问能力
public | protected | default(空的) | private | |
---|---|---|---|---|
同类 | yes | yes | yes | yes |
同包不同类 | yes | yes | yes | no |
不同包子父类 | yes | yes | no | no |
不同包非子父类 | yes | no | no | no |
3. 权限修饰符的使用建议
- 属性:使用
private
,遵循封装原则。 - 成员方法:使用
public
,便于调用。 - 构造方法:使用
public
,便于创建对象。
第二章:final关键字
1. final修饰类
被final
修饰的类不能被继承。
public final class Animal {
}
2. final修饰方法
被final
修饰的方法不能被重写。
public abstract class Animal {
public final void eat() {
System.out.println("动物要干饭");
}
}
3. final修饰局部变量
被final
修饰的变量不能二次赋值。
public class Test01 {
public static void main(String[] args) {
final int i = 10;
//i = 20; 错误:变量i已经被final修饰,不能二次赋值
}
}
4. final修饰对象
被final
修饰的对象,其地址值不能改变,但对象内部状态可以改变。
public class Person {
private String name;
private int age;
public Person() {
}
public Person(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 class Test02 {
public static void main(String[] args) {
//Person p1 = new Person("金莲",26);
//System.out.println(p1);//地址值
//p1 = new Person("涛哥",18);
//System.out.println(p1);//地址值
final Person p1 = new Person("金莲",26);
System.out.println(p1);//地址值
//p1 = new Person("涛哥",18);
//System.out.println(p1);//地址值
p1.setName("大郎");
p1.setAge(30);
System.out.println(p1.getName()+"..."+p1.getAge());
}
}
5. final修饰成员变量
被final
修饰的成员变量需要手动赋值,且不能二次赋值。
public class Student {
final String name = "广坤";
// 有参构造现在属于二次赋值了
/*public Student(String name) {
this.name = name;
}*/
}
第三章:代码块
1. 构造代码块
构造代码块优先于构造方法执行,每new
一次就会执行一次。
public class Person {
public Person() {
System.out.println("我是无参构造方法");
}
{
System.out.println("我是构造代码块");
}
}
2. 静态代码块
静态代码块优先于构造代码块和构造方法执行,且只执行一次。
public class Person {
public Person() {
System.out.println("我是无参构造方法");
}
{
System.out.println("我是构造代码块");
}
static {
System.out.println("我是静态代码块");
}
}
3. 静态代码块使用场景
静态代码块适用于初始化只需要执行一次的静态成员。
第四章:内部类
当一个事物的内部,还有一个部分需要完整的结构去描述,而这个内部的完整结构又只为外部事物提供服务,那么整个内部的完成结构最好使用内部类
比如: 人类都有心脏,人类本身需要用属性,行为去描述,那么人类内部的心脏也需要心脏特殊的属性和行为去描述,此时心脏就可以定义成内部类,人类中的一个心脏类
1. 静态成员内部类
静态内部类可以被final
或abstract
修饰,且不能调用外部的非静态成员。
public class Person {
public void eat() {
System.out.println("人要干饭");
}
static class Heart {
public void jump() {
System.out.println("心脏哐哐哐跳");
}
}
}
public class Test01 {
public static void main(String[] args) {
// 外部类.内部类 对象名 = new 外部类.内部类()
Person.Heart heart = new Person.Heart();
heart.jump();
}
}
2. 非静态成员内部类
非静态内部类可以访问外部类的所有成员,包括私有成员。
public class Person {
public void eat() {
System.out.println("人要干饭");
}
class Heart {
public void jump() {
System.out.println("心脏哐哐哐跳");
}
}
}
public class Test01 {
public static void main(String[] args) {
// 外部类.内部类 对象名 = new 外部类().new 内部类()
Person.Heart heart = new Person(). new Heart();
heart.jump();
}
}
外部类的成员变量和内部类的成员变量以及内部类的局部变量重名时,怎么区分?
public class Student {
String name = "金莲";
class Heart{
String name = "大郎";
public void display(String name){
System.out.println(name);//内部类的局部变量
System.out.println(this.name);//内部类的成员变量
System.out.println(Student.this.name);//外部类的成员变量
}
}
}
public class Test02 {
public static void main(String[] args) {
Student.Heart heart = new Student().new Heart();
heart.display("涛哥");
}
}
3. 局部内部类
局部内
部类可以定义在方法中、代码块中、构造中。
public class Person {
public void eat() {
class Heart {
public void jump() {
System.out.println("心脏哐哐哐的跳");
}
}
new Heart().jump();
}
}
public class Test01 {
public static void main(String[] args) {
Person person = new Person();
person.eat();
}
}
4. 匿名内部类
匿名内部类是没有显式声明类名的内部类,常用于简化代码和实现接口。
问题描述: 我们如果想实现接口,简单使用一次抽象方法,我们就需要创建一个实现类,实现这个接口,重写抽象方法,还要new实现类对象,所以我们在想如果就单纯的想使用一次接口中的方法,我们能不能不这么麻烦呢?可以
- 创建实现类,实现接口
- 重写方法
- 创建实现类对象
- 调用方法
如果就想单纯的使用一下接口中的方法,我们就没必要经过以上四步了,我们可以四合一
匿名内部类怎么学:就按照一种格式来学,这一种格式就代表了实现类对象或者子类对象
new 接口/抽象类(){
重写方法
}.重写的方法();
=================================
类名 对象名 = new 接口/抽象类(){
重写方法
}
对象名.重写的方法();
public interface USB {
void open();
void close();
}
public class Test01 {
public static void main(String[] args) {
new USB(){
@Override
public void open() {
System.out.println("usb打开了");
}
@Override
public void close() {
System.out.println("usb关闭了");
}
}.open();
System.out.println("===================");
USB usb = new USB() {
@Override
public void open() {
System.out.println("USB打开了");
}
@Override
public void close() {
System.out.println("USB关闭了");
}
};
usb.open();
usb.close();
}
}
-
什么时候使用匿名内部类: 当简单调用一次接口中的方法,我们就可以使用匿名内部类
-
将一种格式代表实现类对象或者子类对象来看待,来学习
-
匿名内部类会编译生成的,咱们不要管,我们只需要利用咱们讲的格式去new对象,调用重写的方法即可