一周总结 面向对象
面向对象分为几大模块
封装 继承 多态 称为面向对象的三大特征
之后学习了 静态 final 抽象 接口 代码块 类的初始化 实例初始化
封装
就是把一个功能 或者**封装起来
主要涉及到 public protected 缺省 private(这一块没有很好的理解,)
public 只要在本模块下中都可以访问,使用
protected 本包以及本模块下的其他包中非子类都可以使用(这一块有问题。需要重新的再理解)
缺省:默认的,只可以在本包下可以使用
private: 只可以在本类才可以使用
继承
有一个子类 有一个父类 ,
子类可以继承父类 的属性和方法
这一块主要是 继承之后的方法可以重写,重写之后子类对象调用方法,优先执行子类的重写方法
重写 与重载
方法 可以重写,也可以重载
重写
重写:子类继承父类可以重写父类的方法, 子类如果重写父类的方法,子类对象调用的时候优先调用本类 的重写方法,如果没有重写。
那么,会从父类中找 继承过来的 方法
如果调用了 父类继承过来的方法之后 ,方法体内用到了 实例变量—a ,那么此时的变量a 是父类的 a,
父类没有声明变量 a 子类声明了变量a 但是父类的方法使用了a,编译会报错,即使子类继承父类,那么也会报错
public class exer {
public static void main(String[] args) {
Student s = new Student();
s.show();
}
}
class Person {
// int a= 10;
void show() {
System.out.println(a); // 这块的a会报错
}
}
class Student extends Person {
int a = 5;
void show() {
System.out.println(a);
}
}
方法:追根溯源
变量:就近一致
子类继承父类 只要是子类调用的是父类的方法,那么就会就近使用父类的变量,
子类如果重写了父类的方法,那么 子类对象在调用方法时执行的是子类自己的方法,这个时候就会优先使用子类自己的变量。
子类如果没有这个变量,才会使用父类继承过来的变量。
public class exer {
public static void main(String[] args) {
Student s = new Student();
s.show();
}
}
class Person {
int a= 10;
void show() {
System.out.println(a);
}
}
class Student extends Person {
// int a = 5;
void show() {
System.out.println(a); // 这个时候使用的是自己的方法,会优先在本类中找a,发现没有,那么使用父类继承过来的a
}
}
假如 方法体内声明了一个局部变量a 那么执行那个方法就会优先使用哪个方法体内的局部变量(就近一致)
这边一个小插入
局部变量 和 全局变量
局部变量:声明在 方法体内 随着方法的调用出生 随着方法的结束 结束 局部变量 需要初始化才可以使用
全局变量:声明在类中方法外,随着对象的创建,开辟空间 有默认值
重载
构造器是方法的重载
重载代表的是方法根据 不同的需求 ,去写的不同的方法。 重写则完全的将方法修改,覆盖。
多态
我的理解:多态是一个叠加的状态 ,一个子类可以属于另一个父类, 父类可以创建子类的对象。
代码:
Person p = new Student;
多态的三种应用方式
1.多态应用在形参:父类类型做形参类型 可以接受任意子类对象
2.多态应用在数组: 父类类型做数组类型 可以接受任意子类对象
3.多态应用在返回值类型: 父类类型做返回值类型 可以接受任意子类对象
编译看左边 运行看右边
如果一个程序使用了多态,编译的时候一定是按照父类进行编译的,如果父类编译不通过,那么程序就会报错。
public class exer2 {
public static void main(String[] args) {
// 使用多态
Person p = new Student();
p.show; // 报错,因为编译的时候 Person类没有show方法。
}
}
class Person {
}
class Student extends Person {
void show() {
System.out.println("this is show");
}
}
如果 父亲编译通过之后 程序会优先执行子类中的重写父类方法 ,子类如果没有重写父类的方法,就会向上寻找父类。
假如方法有形参,那么
编译时 先优先寻找最匹配的方法,如果没有,只能退而求其次,使用一个父类或者其他可以接收实参的方法。
运行时 也同样优先调用子类重写的方法,如果没有会线上寻找父类。
package com.atguigu.homework3;
public class Test03 {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println("(1)" + a1.show(b));
System.out.println("(2)" + a2.show(d));
System.out.println("(3)" + b.show(c));
System.out.println("(4)" + b.show(d));
}
}
class A{
public String show(D obj){
return ("A and D");
}
public String show(A obj){
return "A and A";
}
}
class B extends A{
public String show(B obj){
return "B and B";
}
public String show(A obj){
return "B and A";
}
}
class C extends B{
}
class D extends B{
}
(1)A and A
(2)A and D
(3)B and B
(4)A and D
几个关键字的理解
static:
static 静态
static 可以修饰 变量 方法
修饰变量时:静态 变量保存在方法区内:所有对象共享一个数据,
非静态的话,变量是保存在堆里边,每个对象在new 的时候都会在堆中创建一块空间,变量保存在自己的空间当中,对象之 间是彼此分离的。
修饰方法时:静态方法 类名.方法名 调用
非静态: 对象名.方法名
static 修饰的 方法称为静态方法,不能调用静态的资源
原因:static修饰的方法是随着类的加载而开辟空间, 而非静态资源是随着对象的创建而创建的;
所以在非静态资源还没有生成的时候可能类已经在加载了,这个时候肯定不能使用非静态的资源。
解决:
创建对象,进行引用;
public class Test {
public static void main(String[] args) {
Person.sum();
}
}
public class Person {
int a=10;
static void sum(){
// System.out.println(a); 报错 静态方法不能直接使用非静态资源
// 需要创建对象 才可以使用非静态资源
Person p = new Person();
System.out.println(p.a);
}
}
静态方法 不能被重写 不能使用this super
final
最终的,不能被改变
final 可以修饰 类 方法 变量
final 修饰类
被修饰的类不能被继承
final修饰方法
修饰的方法不能被重写(重写意味着更改,final是最终的,不能更改)
final 修饰变量
修饰的变量变为常量, 不能再被更改
final修饰的变量必须初始化:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FmORjP2D-1681394285742)(C:\Users\任帅\AppData\Roaming\Typora\typora-user-images\image-20230413165216626.png)]
初始化方式 :
public class Test {
final int a = 10; // 显示赋值
// 构造器赋值
final int b;
public Test(int b) {
this.b = b;
}
//初始化 代码块赋值
final int c;
{
c = 20;
}
/* final int d;
d=25; 报错 这种方式不能给final赋值
*/
}
局部变量:
基本数据类型: 数值不能改变
引用数据类型: 地址值不能改变
成员变量:
必须有赋值动作
抽象 abstract
抽象类
抽象类 可以拥有普通类的所有资源
包括: 变量和方法 使用
但是 抽象类不能创建对象
抽象方法
抽象方法 必须写在抽象类当中,抽象方法天生就是被重写的。不能被 private static final 修饰
抽象方法 写法 没有大括号
public void show();
注意:
一个类如果继承了一个抽象类,那么这个类必须重写抽象类当中的所有抽象方法
接口
我的理解:接口是为了实现类多继承,一个儿子可以拥有多个父亲。
类实现接口可以看作是:类继承接口
那么:
既然是继承 那么就会拥有继承的所有特性 也可以使用多态
接口的成员
1.成员变量 (全局静态常量)
接口内的变量 默认被 public static final 修饰 。
即使我们 在接口中 int a=10;(final 修饰必须被赋值)
那么也是默认有一个 public static final
public static final int a=10;
2.抽象方法
在接口中声明一个方法默认被public abstract修饰
public interface Fly {
public static final int a=10;
void show(); //接口中的方法(抽象方法) 默认被 public abstract 修饰 所以没有{}
// public abstract void show();
}
3.静态方法
默认被 public 修饰 拥有静态方法的特性
4.默认方法
默认被public 修饰
(public)default void show1(){
}
接口使用的注意:
1.如果一个类实现了接口(一个或多个)那么就必须重写接口内所有的抽象方法
否则此类要变为抽象类
2.接口可以多继承
3.如果实现的多个接口内有同名的抽象方法 只会重写一个
4.如果实现的多个接口内有同名的默认方法 则 实现类必须重写此默认方法
重写的方法内 想要调用父接口的默认方法 接口名.super.默认方法名()
Start1.super.study();
Start2.super.study();
5.先继承再实现
6.如果继承的类和实现的接口内有同名的方法 会优先使用 继承中的方法
亲爹优先
7.如果继承的类和实现的接口内有同名的属性 使用时必须指明来自于哪个类或者接口
内置接口
1.对象的克隆
package com.atguigu.clone05;
/*
对象的克隆
1.实现接口 Cloneable
2.重写 Object clone()
3.对象调用方法进行克隆
*/
public class PersonTest {
public static void main(String[] args) throws CloneNotSupportedException {
Person p1 = new Person("张三",20);
System.out.println("p1 = " + p1);
// Person p2 = p1;
//多态
Object clone = p1.clone();
//todo 使用子类自己独有的属性 需要向下转型
Person p = (Person)clone;
p.name="安琪拉";
System.out.println("p1 = " + p1);
}
}
package com.atguigu.clone05;
public class Person implements Cloneable{
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
String name;
int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
2.对象比较接口
内部比较器 Comparable
package com.atguigu.comparable06.c1;
/*
Comparable: 内部比较器 比较对象
在比较对象类的内部制定比较规则
步骤:
1.让比较对象所在的类 实现 Comparable接口
2.重写 int compareTo()方法制定比较规则
会使用this
前一个对象>后一个对象 返回正整数
前一个对象<后一个对象 返回负整数
前一个对象==后一个对象 返回0
Double.compare(小数, 小数);
3.对象调用比较方法获取结果
*/
public class StudentTest {
public static void main(String[] args) {
Student s1 = new Student("安琪拉",22,99.6);
Student s2 = new Student("吕布",20,99.6);
int compare = s1.compareTo(s2);
System.out.println("compare = " + compare);
}
}
package com.atguigu.comparable06.c1;
public class Student implements Comparable {
private String name;
private int age;
private double score;
@Override
public int compareTo(Object o) {
Student s = (Student) o;
/* if(this.score>s.score){
return 1;
}else if(this.score<s.score){
return -1;
}else{
return 0;
}*/
//return (int)(this.score-s.score);
int compare = Double.compare(this.score, s.score);
return compare;
}
/**
* 向上转型:Object o = s2
*
*
* @return
*/
/* public int compareTo(Object o) {
//this: s1
//使用子类自己独有资源 向下转型
Student s = (Student) o;
return this.age - s.age;
}*/
public Student(String name, int age, double score) {
this.name = name;
this.age = age;
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
}
外部比较器 Comparator
/*
外部/定制比较器:用来比较对象
1.创建一个比较规则类 实现 Comparator接口
2.重写方法 制定比较规则
前一个对象>后一个对象 返回 正整数
前一个对象<后一个对象 返回 负整数
前一个对象==后一个对象 返回 0
3.在需要比较对象的位置创建 比较规则类对象
4.使用比较规则类对象调用方法比较要比较的对象
Dog 类
String name ;
double height;
*/
package com.atguigu.comparator01.c1;
import java.util.Comparator;
//比较规则类
public class SortStudentByScore implements Comparator {
/**
多态的向上转型
Object o1 = s1;
Object o2 = s2;
*/
public int compare(Object o1, Object o2) {
//使用子类自己独有的资源 需要向下转型
Student s = (Student) o1;
Student s1 = (Student) o2;
return Double.compare(s.score,s1.score);
}
}
package com.atguigu.comparator01.c1;
public class Student implements Comparable{
String name;
int age;
double score;
@Override
public int compareTo(Object o) {
//按照年龄比较
Student s = (Student) o;
return this.age-s.age;
}
public Student(String name, int age, double score) {
this.name = name;
this.age = age;
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
}
@org.junit.Test
public void test02(){
//todo 使用外部比较器
Student s1 = new Student("安琪拉",20,98.6);
Student s2 = new Student("妲己",19,98.8);
//创建比较规则类对象
SortStudentByScore sortStudentByScore = new SortStudentByScore();
//使用比较规则类对象调用方法比较要比较的对象
int compare = sortStudentByScore.compare(s1, s2);
System.out.println("compare = " + compare);
}
内部类
内部类顾名思义就是生命在 类里面的类
内部类分为四种
1.成员内部类
成员内部类 就和类中的属性和方法同等地位
可以被 四种权限修饰符修饰 不能使用静态的资源(属性 和方法 ),但是可以存在静态的常量 (static final 在一块)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-izo7YlFD-1681394285743)(C:\Users\任帅\AppData\Roaming\Typora\typora-user-images\image-20230413211118434.png)]
内部类可以使用外部类 的资源
外部类也可以使用内部类的资源 : 需要先创建外部类对象 之后 外部类对象.内部类
外部类名.内部类名 对象名 = new 外部类名().new 内部类名();
Outer.Inner inner = new Outer().new Inner();
2.静态成员内部类
也是写在类中 只不过用static 修饰
可以存在静态的资源
内部类访问外部类
可以直接访问外部类的静态资源 外部类的非静态资源 需要创建外部类对象访问 (与静态方法访问非静态资源一个道理)
外部类访问内部类
访问静态资源 :外部类名.内部类名.资源名
非静态:内部类对象名.资源名
其他类访问内部类
其他类使用内部类资源
静态资源 外部类名.内部类名.资源名
非静态资源
外部类名.内部类名 对象名 = new 外部类名.内部类名();
对象名.资源名
3.局部内部类
**6.如果局部内部类使用了所在方法的局部变量 则此变量默认+final *** 很重要
局部内部类:写在方法内的内部类
位置: 方法内
注意:
1.权限修饰符只能是 缺省的
2.局部内部类中 不能使用静态资源
3.局部内部类使用外部类的资源类型 由所在方法决定
4.局部内部类也有作用域限制
5.局部内部类也会生成独立的字节码文件 命名方式
外部类名$序号内部类名.class 序号从1开始
OuterTest$1A.class
6.如果局部内部类使用了所在方法的局部变量 则此变量默认+final *****
jdk8及其以后 自动+final
jdk8前 需要手动+final
4.匿名内部类 (重点)
记忆这种写法,就等于是创建了一个这个类的子类 和对象 因此也可以继承 多态
大括号后.资源 也可以调用资源
匿名内部类:没有名字的内部类
场景: 简化显示创建对象操作
创建匿名内部类的方式:
1. new 类(){} 既可以是普通类也可以是抽象类
2. new 接口(){}
匿名内部类创建成功后的意义:
1.创建了该类/接口的匿名[子类]
2.完成了该匿名子类对象的创建
注意:
1.匿名内部类也会产生独立的字节码文件命名方式
外部类名$序号.class
Test$1.class Test$2.class
2.匿名内部类是特殊的局部内部类 使用了所在方法的局部变量 变量会+final修饰
父类
public class Person {
String name;
int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void show(){
System.out.println("this is Person show");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
子类
public void test03() {
new Person() {
@Override
public void show() {
System.out.println("匿名子类中重写的方法");
}
}.show();
}
代码块
在类中方法外 用 { } 包括的代码 在对象声明的时候编译运行 (创建一个对象执行一次)
成员代码块(构造代码块)
成员代码块/构造代码块:
位置:类中方法外
作用: 1.可以给成员变量赋值
2.可以将构造器中重复的逻辑提取到代码块内
注意:
1.创建一次对象执行一次
2.先于构造器执行
3.有多个成员代码块时 从上到下依次执行
4.代码块有作用域限制
静态代码块
加 static修饰的代码块 (只会执行一次 )
3.2静态代码块:
位置: 类中方法外
作用: 可以给静态成员变量赋值
初始化作用
注意:
1.静态代码块只会执行一次
2.静态代码块先于普通代码块执行
初始化
先父类初始化-----子类初始化-------实例初始化
实例初始化 的时候 要注意 顺序
尤其注意 每一个类构造器中 第一行的位置 都会默认存在一个 super();
super(); 会调用父类的构造器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XUf72ylY-1681394285744)(C:\Users\任帅\AppData\Roaming\Typora\typora-user-images\image-20230413214954211.png)]
四.初始化
4.1类的初始化:
目的: 给类中的静态成员变量赋值的过程
内容:编译器会自动生成一个<clinit>
静态成员变量显示赋值语句
静态代码块内容
谁先写谁先执行
注意:
0.只要使用了类中的静态资源
创建对象 会触发类的初始化
1.类的初始化只会执行一次
2.如果存在继承关系 会先执行父类初始化再执行子类初始化
4.2实例初始化
目的: 给类中的非静态成员变量赋值的过程
内容:编译器会自动生成一个方法<init>
①super()
②普通成员变量显示赋值语句
③普通代码块内容
④构造器内容
执行顺序: ①②③④
①③②④
4.3混合初始化
类初始化 --> 实例初始化
父类 --> 子类
块只会执行一次
2.静态代码块先于普通代码块执行
## 初始化
先父类初始化-----子类初始化-------实例初始化
实例初始化 的时候 要注意 顺序
**尤其注意 每一个类构造器中 第一行的位置 都会默认存在一个 super();**
**super(); 会调用父类的构造器**
[外链图片转存中...(img-XUf72ylY-1681394285744)]
```Java
四.初始化
4.1类的初始化:
目的: 给类中的静态成员变量赋值的过程
内容:编译器会自动生成一个<clinit>
静态成员变量显示赋值语句
静态代码块内容
谁先写谁先执行
注意:
0.只要使用了类中的静态资源
创建对象 会触发类的初始化
1.类的初始化只会执行一次
2.如果存在继承关系 会先执行父类初始化再执行子类初始化
4.2实例初始化
目的: 给类中的非静态成员变量赋值的过程
内容:编译器会自动生成一个方法<init>
①super()
②普通成员变量显示赋值语句
③普通代码块内容
④构造器内容
执行顺序: ①②③④
①③②④
4.3混合初始化
类初始化 --> 实例初始化
父类 --> 子类