文章目录
对象 和 类
面向对象
编程思想:面向对象、面向过程
Java 是一种完全面向对象的编程语言
Java 中所有的代码都要写在类中,即 类 是Java的基本单位
定义 | 例子 | 组成 | |
---|---|---|---|
类 | 对现实生活中一类具有 共同属性 和 行 为的事物的抽象 确定对象将会拥有的 属性 和 行为 | 手机的各项参数 | 属性 和 行为 |
对象 | 能够看得到摸的着的真实存在的实体 | 实际的手机 |
类
类的特点
- 先有 类 后有 对象
- 类 是 对象 的 数据类型
- 是Java程序的 基本组成单位
类的组成: 属性和行为
属性:在类中通过 成员变量 来体现(类中方法外的变量)
行为:在类中通过 成员方法 来体现(和前面的方法相比去掉static关键字即可)
类的定义步骤
-
定义类
类 不用写 main方法public class 类名{ }
-
编写类的成员变量
public class 类名{ //成员变量 数据类型 变量1; 数据类型 变量2; ... }
-
编写类的成员方法
public class 类名{ //成员变量 数据类型 变量1; 数据类型 变量2; ... // 成员方法 方法1; 方法2; ... }
示例:手机类
类名:
手机(Phone)
成员变量:
品牌(brand)
价格(price)
成员方法:
打电话(call)
发短信(sendMessage)
// 手机 类
public class Phone {
//成员变量
String brand;
int price;
//成员方法
public void call() {
System.out.println("打电话");
}
public void sendMessage(){
System.out.println("发短信");
}
}
对象
万物皆对象,客观存在的事物皆为对象
对象的属性
对象具有的各种特征,每个对象的每个 属性 都拥有特定的值
例如:这个手机的各项属性和对应的参数
对象的行为
对象能够执行的操作
例如:这个手机可以打电话、发短信
对象的使用
-
创建对象
~ 语法 格式 类名 对象名 = new 类名(); 范例 Phone p = new Phone(); 后面基本上是通过 反射 来创建对象
-
使用对象
~ 使用 成员变量 使用 成员方法 格式 对象名.变量名 对象名.方法名() 范例 p.brand p.call()
定义 手机测试类
类名:PhoneDemo
- 因为要做测试,所以要写一个主方法: main方法
- 给 成员变量 赋值 ,输出成员变量的值
调用 成员方法
// 手机 测试类
public class PhoneDemo {
public static void main(String[] args) {
//创建对象
Phone p = new Phone();
//使用成员变量
System.out.println(p.brand); // null
System.out.println(p.price); // 0
p.brand = "小米";
p. price = 2999;
System.out.println(p.brand); // 小米
System.out.println(p.price); // 2999
// 使用成员方法
p.call(); // 打电话
p.sendMessage(); // 发短信
}
}
定义数组对象数组
一定不要忘了这一步:students[i] = new Student();
// 构造方法
Student[] students = new Student[5];
// 每个数据的初始化
for(int i = 0;i < students.length;i++) {
students[i] = new Student();
}
对象内存图
单个对象
成员方法:
一个地址的大小看JVM的位数,是64位的就是64个字节
成员变量:
多个对象
- 成员变量
成员变量 的值是 唯一 的
- 成员方法
成员方法 多个方法 是可以 共用 的
多个对象指向相同
成员变量和局部变量
区别 | 局部变量 | 成员变量 |
---|---|---|
类中位置不同 | 方法内 或者 方法声明上,即形参 | 类中方法外 |
内存中位置不同 | 栈内存 | 堆内存 |
生命周期不同 | 随着方法的调用而存在,随着方法的调用完毕而消失 | 随着对象的存在而存在,随着对象的消失而消失 |
初始化值不同 | 没有默认的初始化值,必须先定义,赋值,才能使用 | 有默认的初始化值 |
封装
-
封装概述
是面向对象三大特征之一(封装,继承,多态)是 面向对象 编程语言对客观世界的模拟,客观世界里 成员变量 都是隐藏在对象内部的,外界是无法直接操作的
-
封装原则
将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问成员变量 private,提供对应的 getXxx()/ setXxx() 方法 -
封装好处
通过方法来控制成员变量的操作,提高了代码的 安全性
通俗点说就是“脱了裤子放屁”,对裤子安全
把代码用方法进行封装,提高了代码的 复用性 -
广义封装
将学生、老师分别编写一个类 -
狭义封装
学生,老师,编写一个类,功能相对集中
将类中的属性私有化(使用private修饰)
提供公共get和set方法操作属性
private 关键字
- 是一个 权限修饰符
- 可以修饰成员(成员变量和成员方法)
- 作用是保护成员不被别的类使用,被 private 修饰的成员只在 本类 中才能访问
被其他类使用
针对 private 修饰的成员变量,如果需要被其他类使用,有两种 方法
格式 | 作用 | 修饰 |
---|---|---|
get变量名() | 用于 获取 成员变量的值 | 方法用 public修饰 |
set变量名(参数) | 用于 设置 成员变量的值 | 方法用 public 修饰 |
注意: 变量名 的 首字母大写 |
封装的作用
问什么要用 封装?
案例
↓ 没有封装的情况
public class Student {
// 成员变量
String name;
int age;
// 成员方法
public void show( ) {
System.out.println(name + "," + age);
}
}
// 学生测试类
public class StudentDemo {
public static void main(String[]args) {
// 创建对象
Student s = new Student();
// 给成员变量赋值
s.name ="小李";
// s.age = 30;
s.age = -30;
//调用show方法
s.show(); // 小李,-30
}
}
人的年龄输出了负数,这代码是不行的
因此在 类 里加了一个判断,在输入错误时进行提示
public class Student {
// 成员变量
String name;
// int age;
private int age;
//提供get/set方法
public void setAge(int a) {
age = a;
if(a < 0 || a > 250) {
System.out.println("你给的年龄有误");
} else {
age = a;
}
}
public int getAge() {
return age;
}
// 成员方法
public void show( ) {
System.out.println(name + "," + age);
}
}
// 学生测试类
public class StudentDemo {
public static void main(String[]args) {
// 创建对象
Student s = new Student();
// 给成员变量赋值
s.name ="小李";
// s.setAge(30);
s.setAge(-30); // 你给的年龄有误
s.show( ); // 小李,-30
}
}
private 格式
public class Student {
//成员变量
private String name;
private int age;
// get set方法
public void setName(String n) {
name = n;
}
public String getName( ) {
return name;
}
public void setAge(int a) {
age = a;
}
public int getAge( ) {
return age;
}
public void show() {
System.out.println(name + "," + age);
}
}
// 学生测试类
public class studentDemo {
public static void main( string[] args) {
// 创建对象
Student s = new Student();
//使用set方法给成员变量赋值
s.setName(“小李");
s.setAge(30) ;
// 两种输出的方法
s.show(); // 小李,30
// 使用get方法获取成员变量的值
System.out.println(s.getName() + "---" + s.getAge()); // 小李---30
}
}
this 关键字
this修饰的 变量 用于指代 成员变量
是为了解决 局部变量 隐藏 成员变量
this代表所在 类 的 对象 引用
注意: 方法 被哪个 对象 调用,this 就代表哪个 对象
不带 this修饰 的 变量
情况 | 与 成员变量 同名 | 不与 成员变量 同名 |
---|---|---|
形参 | √ | × |
成员变量 | × | √ |
方法 的 形参 如果与 成员变量 同名,不带 this修饰 的 变量 指的是 形参 ,而不是 成员变量
方法 的 形参 不与 成员变量 同名,不带this修饰的变量指的是成员变量
this 有什么用
写代码要做到 见名知意
public void setName (String n) {
name = n;
}
因此改成下面这样
但是名字会输出 null
public void setName(String name) {
name = name;
// 改为
this.name = name;
}
构造方法
无论干什么,先写无参构造方法!!!
作用: 创建对象
功能: 主要是完成 对象 数据的 初始化
格式:
public class 类名{
修饰符类名(参数){}
}
示例:
public class Student {
public Student () {
// 构造方法内书写的内容
}
}
案例:
public class studentDemo {
public static void main(String[] args) {
// 创建对象
Student s = new Student(); // 无参构造方法
}
}
public class Student {
// 构造方法
// 调用 无参构造 方法
public Student() {
System.outprintln("无参构造方法");
}
}
注意:
只写这个,Student.java 里不写构造方法也不会报错,因为系统会给一个 无参构造方法
Student s = new Student();
有参构造方法
创建 有参构造方法 同时必须创建 无参构造方法 解释
有参与带参构造方法的关系就是构造方法的重载
Teacher t1 =.new Teacher( );
t1.setName("小李");
t1.setAge(20) ;
System.out.println(t1.getName() + "," + t1.getAge()); // 小李,20
Teacher t2 = new Teacher("小张", 25);
System.out.println(t2.getName() + "," + t2.getAge()); // 小张,25
构造方法的注意事项
父类 使用 子类 中的 有参 构造方法
public class Student extends Person {
public Student (String name, int age) {
// 这样写不对
// this.name = name;
// this.age = age;
super(name,age);
}
}
- 构造方法的 创建
情况 没有 定义构造方法 定义了构造方法 系统 给出一个 默认 的 无参数构造方法 不 提供默认的构造方法
- 构造方法的 重载
自定义了 有参构造方法 后,还要使用 无参数构造方法 ,就必须再写一个 无参数构造方法 - 构造方法的 重写
要有参数列表的不同
建议: 无论是否使用,推荐都写 无参数构造方法
标准类制作
-
成员变量
使用private修饰 -
构造方法
提供一个 无参构造方法
提供一个 带多个参数的有参构造方法 -
成员方法
提供每一个成员变量对应的 setXxx() getXxx()
提供一个显示对象信息的 show() -
创建 测试类 对象 并为其 成员变量 赋值的两种方式
- 无参构造方法创建对象后使用setXxx()赋值
- 使用带参构造方法直接创建带有属性值的对象
总结:
学生类 Student.java 是用来放 方法 和 参数 的地方
学生测试类 StudentDemo.java 来调用那些 学生类 里的 方法并向 学生类 里传递 参数
private String name;
private int age;
public Student(String name) {
this.name = name;
}
public Student(int age) {
this.age = age;
}
public void show( ) {
System.out.println(name+ "," +age);
}
当有参数时系统给默认无参构造方法就不再适用了
// 因此要在这里给出一个无参构造方法,否则报错
public Student(){}
student s1 = new Student();
s1.show( ); // null,0
Student s2 = new Student( name:"小李");
s2.show( ); // 小李,0
Student s3 = new Student( name:“小李", age: 30);
s3.show(); // 小李,30
继承 extends
- 继承 是 面向对象 三大特征之一
- 是类与类之间最强的关系
- 可以使得 子类 具有 父类 的 属性 和 方法 ,还可以在 子类 中重新定义,追加属性和方法
继承有什么用?
继承的格式
关键词 | 格式 |
---|---|
extends | public class 子类名 extends 父类名 |
范例: | |
public class Zi extends Fu {} |
位置 | 类 | 别称 |
---|---|---|
前者 | 子类 | 基类、超类 |
后者 | 父类 | 派生类 |
继承中子类的特点
-
子类 可以有 父类 的内容
-
子类还可以有自己 特有 的内容
案例:
public class Father {
public void me() {
System.out.println("Father类被调用");
}
}
public class Son extends Father {
public static void you() {
System.out.println("Son类被调用");
}
}
public class Demo {
public static void main(String[] arge) {
// 无参构造方法创建对象
Father f = new Father();
f.me();
Son son = new Son();
son.you();
son.me();
}
}
好处和弊端
继承的 好处
- 提高了代码的 复用性
多个类相同的成员可以放到同一个类中 - 提高了代码的 维护性
如果方法的代码需要修改,修改一处即可
继承的 弊端
继承让类与类之间产生了关系,类的 耦合性 增强了,当父类发生变化时子类实现也不得不跟着变化,削弱了子类的 独立性
什么时候使用继承?
有两个类A和B,如果他们满足A是B的一种,或者B是A的一种,就说明他们存在继承关系,这个时候就可以考虑使用继承来体现,否则就不能滥用继承
比如:Java 和 编程语言 √ 单身狗 和 狗 ×
继承中的变量
在子类方法中访问一个变量
- 子类 局部 范围找 ↓
- 子类 成员 范围找 ↓
- 父类 成员 范围找 ↓
- 如果都没有就报错
super
可以参考 this 关键字
this:代表 本类 对象的引用
super:代表 父类 对象的引用
引用 即是存储空间的 标识
关键字 | 访问成员变量 | 访问构造方法 | 访问成员方法 |
---|---|---|---|
this | this.成员方法 访问本类成员变量 | this(…) 访问本类构造方法 | this.成员方法(…) 访问本类成员方法 |
super | super.成员变量 访问父类成员变量 | super(…) | super.成员方法(…) 访问父类成员方法 |
要想调用第三个可以改成 this(name, 18);
案例:
public class Father {
public int age = 3;
}
public class Son extends Father {
public int age = 2;
public void you() {
int age = 1;
System.out.println("本类局部变量:" + age); // 本类局部变量:1
System.out.println("本类成员变量:" + this.age); // 本类成员变量:2
System.out.println("父类变量:" + super.age); // 父类成员变量:3
}
}
访问构造方法
子类中所有的构造方法 默认 都会访问父类中 无参 的构造方法
1. 父类数据的初始化
因为子类会继承父类中的数据,可能还会使用父类的数据
所以,子类初始化之前,一定要先完成父类数据的初始化
父类数据的初始化:访问父类的构造方法
案例:
public class Father {
public Father(){
System.out.println("父类 中 无参 构造方法");
}
public Father(int age) {
System.out.println("父类 中 带参 构造方法");
}
}
public class Son extends Father {
public Son() {
System.out.println( "子类 中 无参 构造方法");
}
public Son(int age){
System.out.println( "子类 中 带参 构造方法");
}
}
public class Demo {
public static void main(String[] args) {
// 创建对象
// 无参构造方法
Son z1 = new Son();
// 父类 中 无参 构造方法
// 子类 中 无参 构造方法
// 有参构造方法
Son s2 = new Son(25);
// 父类 中 无参 构造方法
// 子类 中 无参 构造方法
// 父类 中 带参 构造方法
// 子类 中 带参 构造方法
}
}
2. 默认 super();
每一个子类构造方法的第一条语句默认都是 super(); 因为没有参数所以访问的父类的无参构造方法
因此如果 父类 的无参构造方法 没了,那 子类 中无论 无参 还是 带参 构造方法都会报错
但是两者都通过 super(20); 来访问 父类 中的 带参 构造方法就没问题了
父类 中最好定义无参构造方法
public Son( ) {
super(20);
System.out.println( "子类 中无参构造方法");
}
public Son(int age){
super(20);
System.out.println( "子类中带参构造方法");
}
构造方法和成员方法的区别,十分简洁明了
访问成员方法
类似于访问变量,都是先子后父
通过子类对象访问一个方法
- 子类 成员 范围找 ↓
- 父类 成员 范围找 ↓
- 如果都没有就报错
案例:
public class Fu {
public void show() {
System.out.print1n( "Fu中show()方法被调用");
}
}
public class Zi extends Fu {
public void method() {
System.out. println("zi中method()方法被调用");
}
public void show(){
System.out. println("zi中show()方法被调用");
}
}
public c1ass Demo {
public static void main(String[] args) {
//创建对象,调用方法
Zi z = new Zi();
z.method();
z.show();
// Zi中没show Zi中没show
// Zi中method()方法 Zi中method()方法
// Fu中show()方法 Zi中show()方法
}
}
public void show(){
super.show();
System.out.println("zi中show()方法被调用");
// Fu中show()方法
// Zi中show()方法
}
方法重写
方法重写和重载
定义:
子类中出现了和父类中一样的方法声明
应用:
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容
public void call( string name) {
System.out.println("给" + name + "打电话");
}
public class NewPhone extends Phone {
public void cal1(String name) {
System.out.println("开启视频功能");
// System.out.println("给" + name + "打电话");
super.call(name); // 重写方法
}
}
public static void main( String[] args) {
//创建对象,调用方法
Phone p = new Phone();
p.call("小李"); // 给小李打电话
NewPhone np = new NewPhone();
np.call("小李");
}
注意事项
私有方法不能被重写(父类私有成员子类是不能继承的)
子类方法 访问权限 不能更低(public >默认>私有)
注解:@Override
说明是重写父类的方法,检测正确性
如果重写的语句写错了会报错
@Override // 方法名不同,报错
public void cabcll(String name) {
}
继承的注意事项
1. 只支持单继承,不支持多继承
// 报错
public class Son extends Fathen, Mother {
}
2. 支持多层继承
public class Fathen extends Granddad {
}
public class Son extends Fathen {
}
包
定义:包就是文件夹
作用:对 类 进行分类管理
包的定义格式
格式: package 包名; (多级包用 . 分开)
范例:
package com.task;
导包
使用别的包中的类
- 加上前缀
cn.task.Teacher t = new cn.task.Teacher();
- 导包
和控制台输入和随机数一样
格式: import 包名;import cn.task.Teacher; Teacher t = new Teacher();
修饰符
权限修饰符
注意:
第三种会报错,因为 它不是基于继承来得到的
状态修饰符
final (最终态)
类
被 final 修饰的类是最终类不能被继承
最终到空前绝后了,没后代了
public final class Fu { }
public ciass zi extends Fu { } // 报错
方法
子类将不能重写这个方法
public final void method( ) {
System.out.println( "Fu method" );
}
定义 常量
public final int age = 20;
public void show() {
age = 100; // 报错
System.out.println(age); // 20
}
引用类型
引用类型的地址不能变,但是内容可以变
// final修饰引用类型变量
fina1 Student s = new Student();
s.age = 100;
System.out.println(s.age); // 100
s = new Student(); // 报错
static(静态)
被static修饰的东西,都是静态的
直属于类,与对象无关
可以修饰成员方法,成员变量,静态内部类
// 静态内部类
static class TestA {
}
- 被类的所有对象共享
- 可以通过类名调用
也可以通过对象名调用
public string name; //姓名
// public string school;
public static String school; // 学校
1
Student.school = "a大学"; // 通过类名来访问,写在这里更好
2 // 这两种都一样
Student s = new Student();
s.school = "a大学";
Student s1 =.new Student();
s1.name ="小李";
s1.school="a大学"; // 通过对象名来访问,可以这样写
// 他们都是来至同一所大学
Student s2 = new Student();
s2.name = "小张";
// s2.school ="a大学";
static访问特点
非静态的成员方法 能访问 ↓
静态 成员变量
静态 成员方法
非静态 成员方法
非静态 成员变量
静态的成员方法 能访问 ↓
静态 成员变量
静态 成员方法
但是间接访问可以
总结:静态成员方法 只能访问 静态成员
静态常量和类加载的过程
- 代码在静态块中,不定义直接赋值不会报错
- 对于已经有值的变量,再次定义将不会赋类0值
静态和继承
- 父类 静态代码
- 子类 静态代码
- 父类 非静态代码
- 父类 构造方法
- 子类 非静态方法
- 父类 构造方法
在父类的静态代码执行完之前子类的静态代码不能执行
问什么父类和子类的非静态代码可以在前面执行?
类和对象是分开的,静态指类,非静态指对象
多态
同一个对象,在不同时刻表现出来的不同形态
根据何时确定执行多态方法中的哪一个,多态分为两种情况:编译时多态 和 运行时多态
详解
多态的形式:1.具体类多态(用的最少),2.抽象类多态,3.接口多态
举例:这里猫在不同的时刻表现出来了不同的形态,这就是多态
描述 | 体现 |
---|---|
猫是猫 | 猫 cat = new 猫(); |
猫是动物 | 动物 animal = new 猫(); |
多态的前提和体现
三点,记住了三点
- 有继承 / 实现关系
- 有方法重写
- 有 父类引用 指向 子类对象
前提 | 体现 | |
---|---|---|
1 | 有继承 / 实现关系 | public class Cat extends Animal { } |
2 | 有方法重写 | @Override public void eat() { } |
3 | 有父(类/接口)引用指向(子/实现)类对象 | Animal a = new Cat( ); |
成员访问特点
因为成员方法有重写,而成员变量没有
编译 | 执行 | |
---|---|---|
成员变量 | 看左边 | 看左边 |
成员方法 | 看左边 | 看右边 |
public class Animal {
public int age = 40;
public void eat() {
System.out.print1n("动物吃东西");
}
}
public class Cat extends Animal {
public int age = 20;
public int weight = 10;
@Override
public void eat() {
System.out. println("猫吃鱼");
}
public void playGame() {
System.out.println("猫捉迷藏");
}
}
public class AnimalDemo {
public static void main(string[] args) {
// 有父类引用指向子类对象
Animal a = new Cat();
System.out.println(a.age);
System.out.println(a.weight); // 报错
a.eat();
a.pLayGame( ); // 报错
}
}
利弊
好处:提高了程序的扩展性
具体体现:定义方法的时候,使用父类型作为参数,将来在使用的时候,使用具体的子类型参与操作
public static void main( String[] args) {
// 创建动物操作类的对象,调用方法
AnimalOperator ao = new Animal0perator();
Cat c = new Cat();
ao.useAnimal(c); // 猫吃鱼
Dog d = new Dog();
ao.useAnimal(d); // 狗吃骨头
}
public class AnimalOperator {
public void useAnimal(Animal a) {
// Animal a = new Cat();
// Animal a = new Dog();
a.eat();
}
}
弊端:不能使用子类的特有的对象
多态中的转型
有点类似数据类型的转换
上转型
- 从子到父
- 父类引用指向子类对象
- 只能调用父类的方法
下转型
- 从父到子
- 父类引用转为子类对象
- 要想使用使用子类的特有的对象就得用 向下转型
//多态
Animal a = new Cat(); // 向上转型
a.eat();
// a.playGame(); // 报错
//向下转型
Cat c = (Cat)a;
c.eat();
c.playGame();
经典案例
抽象类 abstract
一句话概括:抽象方法抽象类
在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类
比如:猫狗的父类动物类
案例:
public abstract class Animal {
public abstract void eat();
public void sleep() {
System.out.println("睡觉");
}
}
public class Cat extends Animal {
@Override
public void eat() {
system.out.println("猫吃鱼");
}
}
public static void main( String[] args) {
Animal a = new Cat();
a.eat(); // 猫吃鱼
a.sleep(); // 睡觉
}
抽象类的特点
-
抽象类和抽象方法必须使用abstract关键字修饰
public abstract class 类名 { }
public abstract void eat); -
抽象类里面可以没有抽象方法
但是抽象方法一定在抽象类里 -
抽象类实例化(即创建对象)
抽象类不能创建对象,参照多态的方式,通过子类对象实例化,这叫 抽象类多态 -
抽象类的子类
要么重写抽象类中的所有抽象方法
要么是抽象类public abstract class Dog extends Animal { }
成员特点
- 成员变量
可以是变量
也可以是常量 - 构造方法
有构造方法,但是不能实例化
构造方法的作用:用于子类访问父类数据的初始化 - 成员方法
可以有抽象方法:限定子类必须完成某些动作
也可以有非抽象方法:提高代码复用性
接口
本质上是一种数据类型,引用类型
接口更多的体现在对行为的抽象
函数式接口,方法多写一个就报错
public interface Inter {
public abstract void jump();
}
// 接口的实现类 接口名 + Impl
public class InterImpl extends Father implements Inter {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
@Override
public void jump() {
System.out.println("猫可以跳高了");
}
}
接口的特点
- 接口用关键字用 interface 修饰
public interface 接口名 { }
- 类实现接口用 implements 表示
public class 类名 implements 接口名 { }
- 接口不能实例化(即创建对象)
接口可以参照多态的方式实例化
通过实现类对象实例化,这叫 接口多态 - 接口的实现类
要么 重写 接口中的所有抽象方法
要么是 抽象类
成员特点
- 接口中的变量默认被 final 修饰
默认修饰符:public static finalpublic interface Inter { public int num = 1; public final int num2 = 2; } Inter i = new InterImpl(); i.num = 20; // 报错 i.num2 =40; // 报错
- 接口没有构造方法
因为所有类都继承于 Object类,里面只有一个无参构造public interface Inter { // 写这个构造方法会报错 public InterImpl() { } } public class InterImpl implements Inter // 相当于 ↓ public class InterImpl extends Object implements Inter{ public InterImpl() { super( ); } }
- 接口里不能有非抽象方法
接口的方法默认修饰符:public abstract// 报错 public void show( ) {} // 运行 public abstract void method(); // 这样写也行 ↓ void method();
抽象类和接口的关系
关系区别
内容 | 关系 |
---|---|
类 和 类 | 单继承,多层继承 |
类 和 接口 | 多实现 |
接口 和 接口 | 多继承 |
public class InterImpl implements Inter1,Inter2,Inter3 {}
public interface Inter3 extends Inter1,Inter2 { }
成员区别
内容 | 成员 |
---|---|
抽象类 | 变量,常量,有构造方法 有抽象方法,也有非抽象方法 |
接口 | 常量,抽象方法 |
设计理念区别
内容 | 成员 |
---|---|
抽象类 | 对事物抽象,包括属性、行为 |
接口 | 对行为抽象,主要是行为 |
接口的作用
Java是单继承多实现的
接口的 多实现 纯粹就是为了解决类的 单继承
防火&防盗门
形参和返回值
类名作为形参和返回值
① 方法的 形参 是类名,其实需要的是 该类 的对象
public class CatOperator {
// ↓ 相当于 cat c = new Cat();
public void useCat(Cat c) {
c.eat();
}
}
public class CatDemo {
public static void main(string[] args){
//创建操作类对象,并调用方法
Catoperator co = new CatOperator();
Cat c = new Cat();
co.useCat(c);
}
}
② 方法的 返回值 是类名,其实返回的是 该类 的对象
public Cat getCat(){
Cat c = new Cat();
return c;
}
// 表达式的右边相当于 new Cat()
Cat c2 = co.getCat();
c2.eat();
抽象类名作为形参和返回值
① 方法的 形参 是抽象类名,其实需要的是该抽象类的 子类 对象
public void useAnimal(Animal a) {
a.eat();
}
AnimalOperator ao = new Animal0perator();
Animal a = new Cat();
ao.useAnimal(a);
② 方法的 返回值 是抽象类名,其实返回的是该抽象类的 子类 对象
public Animal getAnimal() {
Animal a = new Cat();return a;
}
Animal a2 = ao.getAnimal();
a2.eat( );
接口名作为形参和返回值
方法的 形参 是接口名,其实需要的是该接口的 实现类 对象
public void useJumpping(Jumpping j) {
j.jump();
}
JumppingOperator jo = new JumppingOperator( );
Jumpping j = new Cat( );
jo.useJumpping(j);
方法的 返回值 是接口名,其实返回的是该接口的 实现类 对象
pubiic Jumpping getumpping() {
Jumpping j = new Cat();
return j;
}
// 表达式的右边相当于 new Cat()
Jumpping j2 = jo.getJumpping();
j2.jump();
内部类
在一个类中定义一个类,可以在类的方法里定义
举例:电池类就是手机类的内部类
格式:
public class 类名{
修饰符 class 类名 {}
}
public class outer {
public class Inner {}
// 静态内部类
static class TestA {}
}
public void test() {
public class TestB {}
}
}
内部类的访问特点
- 内部类可以直接访问外部类的成员,包括私有
- 外部类要访问内部类的成员,必须创建对象
案例:
public class Outer {
private int num = 10;
public class Inner {
public void show() {
// 直接访问
System.out.println(num);
}
}
public void method() {
// 报错
show();
// 应该这样写
Inner i = new Inner();
i.show( );
}
}
分类
按照内部类在类中定义的位置不同,可以分为如下两种形式
在类的成员位置:成员内部类
在类的局部位置:局部内部类
成员内部类
创建成员内部类对象
① 直接创建
格式:
外部类名.内部类名 对象名 = 外部类对象.内部类对象;
Outer.Inner oi = new Outer().new lnner();
② 间接创建
之所以建内部类就是为了不让外界直接去使用这个类,因此内部类的修饰符大部分都是私有的
要想创建内部类对象只能通过外部类迂回着创建
public class Outer {
private int num = 10;
private c1ass 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 o = new Outer();
o.method();
}
局部内部类
局部内部类是在方法中定义的类,所以外界是无法直接使用,需要在方法内部创建对象并使用
该类可以直接访问外部类的成员,也可以访问方法内的局部变量
public class Outer {
private int num = 10;
public void method() {
class Inner {
public void show(){
System.out.println(num);
}
}
// 调 内部类Inner 中的 show方法
Inner i = new Inner();
i.show();
}
}
public class outerDemo {
public static void main( String[ ] args) {
Outer o = new Outer();
o.method();
}
}
匿名内部类
前提:存在一个类或者接口,这里的类可以是具体类也可以是抽象类
本质: 是一个继承了该类或者实现了该接口的子类匿名 对象 !
格式:
new 类名或者接口名 () {
重写方法;
}
new Inter( {
publicvoid show() {
}
}
案例:
接口
public interface Inter {
void show();
}
类
public class outer {
public void method() {
1
new Inter() {
@Override
public void show( ) {
System.out.print1n("匿名内部类");
}
};
show(); // 报错,不能这样调用
2
// 将 匿名类Inter 作为一个对象
new Inter() {
@override
public void show( ) {
System.out.println(“匿名内部类");
// OuterDemo: 匿名内部类
}
}.show();
3
// 对象都有返回值类型
// {} 内的内容都可以看做是一个 Inter的实现类对象 ,因此new后面的 Inter 就可以按照多态的方式赋值给前面的接口
Inter i = new Inter( ) {
@Override
public void show() {
System.out.print1n(“匿名内部类");
// OuterDemo: 匿名内部类
}
};
i.show();
}
}
测试类
public class OuterDemo {
public static void main(String[] args) {
outer o = new Outer() ;
o.method();
}
}
应用
可以省下类的创建
接口
public interface Jumpping {
void jump();
}
接口操作类
接口操作类:里面有一个方法的参数是接口名
public c1ass JumppingOperator {
public void method(Jumpping j) {
j.jump();
}
}
测试类
public class JumppingDemo {
public static void main(String[] args) {
//需求:创建接口操作类的对象,调用method方法
方案1
// 这种方法要再创建一个 cat类
JumppingOperator jo = new Jumpping0perator();
Jumpping j = new Cat();
jo.method(j);
方案2
jo.method( new Jumpping() {
@Override
public void jump( ) {
System.out.println("🐖可以跳上🌳了");
}
});
}
}
后续
后续内容在《Java SE基础学习笔记3》