面向对象
面向对象
1 面向对象和面向过程的区别
1.1 都是编程思想
1.2 面向过程注重过程,步骤,怎么做
- 执行者
1.3 面向对象注重对象,谁来做
- 指挥者
2 面向对象学习
2.1 、类与对象
- (1)类与对象的概念
- (2)类与对象的关系
- (3)如何设计类,类的成员
- (4)如何创建对象
2.2 、面向对象的三个基本特征和高级特性
-
基本特性
- 封装
- 继承
- 多态
-
高级特性
- 枚举
- 接口
- 抽象
- 泛型
- 注解
- 可变参数
- 自动装箱与拆箱
- foreach
- Lambda表达式
- …..
2.3 、相关的关键字和API
-
关键字
-
class
-
new
-
this
-
权限修饰符
- public
- protected
- 缺省
- private
-
super
-
…
-
-
API
- 集合
- 异常
- IO
- 网络编程
- 线程
- ….
3 、类与对象
3.1 (1)类与对象的概念
- 类:对一类具有相同特征的事物的抽象描述
- 对象:类的实例,是具体的个体
3.2 (2)类与对象的关系
- 类是对象的设计图,创建的模板
- 对象是类的实例,是一个具体的个体
3.3 (3)类的设计,成员
-
(1)属性
-
属性的特点
-
(1)声明的位置
- 在类中方法外
-
(2)保存的位置
-
static
- 在方法区
-
非static
- 在堆中
-
-
(3)默认值
- byte,short,int,long是0,float,double是0.0,boolean是false,char是\u0000,引用数据类型都是null
-
(4)作用域
- 在整个类中
-
(5)生命周期
- 随着对象的创建而创建,到垃圾回收为止
-
-
属性声明格式
-
[修饰符] 数据类型 属性名 【=显式值】;
-
修饰符
-
private
- 私有化
-
-
-
-
-
(2)构造器
-
构造器的作用
- (1)和new一起创建对象
- (2)为属性赋值
-
如何声明
-
无参
- [修饰符] 类名(){ }
-
有参
- [修饰符] 类名(形参列表){ }
-
-
特点
- 构造器的特点: (1)构造器名与类名必须相同 (2)构造器没有返回值 (3)构造器可以重载 (4)如果一个类没有声明过构造器,编译器将默认添加一个无参构造 如果这个类声明了构造器,编译器将不再自动添加无参构造
-
如何调用
-
(1)和new一起
- new 构造器() new 构造器(实参列表)
-
(2)在本类的其他构造器中或子类的构造器中
- 在本类的其他构造器中:this()或this(实参列表) 在子类的构造器中:super()或super(实参列表)
-
-
-
(3)方法
- 无参无返回值
- 有参无返回值
- 无参有返回值
- 有参有返回值
-
(4)代码块
-
按位置分
-
在类中方法外
-
是否有static修饰
-
有static修饰的:静态代码块
-
语法结构
- class 类{ static{ 静态代码块 } }
-
特点
-
随着类的加载并初始时而执行,而且一个类的静态代码块只执行一次
- 而且父类的静态代码块优先于子类的静态代码块
- 静态代码块肯定优先于构造块和构造器
-
-
作用
- 为静态变量(类变量)初始化(赋值)
-
-
没有static修饰的:非静态代码块,构造块
-
语法结构
- class 类{ { 静态代码块 } }
-
特点
- 每次创建对象时调用,而且先于构造器调用
-
作用
- 为实例变量初始化(赋值),一般是多个构造器中重复的代码提取到构造块
-
-
-
-
在方法中
- 局部代码块(了解)
-
-
相关的面试题
-
赋值和执行的顺序
- 父类的静态代码块 – 》子类的静态代码块 –》父类的构造块–》父类的构造器 –》子类的构造块 –》子类的构造器
-
关于static的重写问题
-
静态的方法和属性,没有编译时类型和运行时类型的区别,只有编译时类型,换句话说没有重写(覆盖)一说
package com.atguigu.static_.buchong;
/*
-
静态的方法:不存在编译时和运行时类型,只有编译时类型
-
静态的属性:不存在编译时和运行时类型,只有编译时类型
*/
public class Test {
public static void main(String[] args) {
SuperClass s = new SubClass(); s.test();//父类的方法 System.out.println(s.info);//尚硅谷
SubClass sub = new SubClass(); sub.test();//子类的方法 System.out.println(sub.info);//atguigu
}
}
class SuperClass{
static String info = “尚硅谷”;
public static void test(){
System.out.println("父类的方法");
}
}
class SubClass extends SuperClass{
static String info = “atguigu”;
public static void test(){
System.out.println("子类的方法");
}
}
-
-
-
-
-
(5)内部类
-
什么情况下使用内部类
- (1)当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类 (2)内部类可以访问外部类的所有的成员,包括私有的
-
形式
-
成员
-
静态内部类
-
格式
- [修饰符] class 外部类{ [修饰符] static class 内部类{ } }
-
修饰符的问题
-
(1)权限修饰符
- 4种
-
(2)static
- 必须得有
-
(3)final(极少)
-
可以
- 表示不能被继承
-
-
(4)abstract(极少)
-
可以
- 表示可以包含抽象方法,需要子类继承
-
-
-
静态内部类的成员
- 所有都可以,包括静态的
-
使用问题
-
(1)在静态内部类中使用外部类的成员
- 只能使用外部类的静态成员
-
(2)在外部类中使用静态内部类
- 都可以
-
(3)在外部类的外面,其他类中
-
(1)用静态内部类的静态成员
- 外部类名.内部类名.静态成员
-
(2)用静态内部类的非静态成员
- 需要静态内部类的对象
- 外部类名.内部类 变量 = new 外部类名.内部类(); 变量.成员….
-
-
-
-
非静态内部类,通常称为成员内部类
-
格式
- [修饰符] class 外部类{ [修饰符] class 内部类{ } }
-
修饰符的问题
-
(1)权限修饰符
- 4种
-
(2)static
- 没有
-
(3)final(极少)
-
可以
- 表示不能被继承
-
-
(4)abstract(极少)
-
可以
- 表示可以包含抽象方法,需要子类继承
-
-
-
非静态内部类的成员
- 除了静态成员,其他都可以
-
使用的问题
-
(1)在非静态成员内部类中使用外部类的成员
- 都可以
-
(2)在外部类中使用非静态成员内部类
-
在外部类的静态成员中不能使用非静态成员内部类
-
静态 (不能用) 非静态
- 原因,静态的成员先加载,非静态只有创建对象才有
-
-
-
(3)在外部类的外面使用非静态成员内部类
-
依赖于外部类的对象
-
形式一
-
(1)先创建外部类的对象
- 外部类 out = new 外部类();
-
(2)通过外部类的对象创建内部类的对象
- 外部类.内部类 in = out.new 内部类();
-
(3)通过内部类对象调用它的成员
- in.成员
-
-
形式二
-
(1)在外部类中提供一个方法,用来返回内部类的对象
- class 外部类{ class 内部类{ }
-
-
-
-
-
-
public 内部类 getInnerInstance(){ return new 内部类(); }
-
}
- (2)创建外部类的对象
- 外部类 out = new 外部类();
- (3)通过外部类的对象,获取内部类的对象
- 外部类.内部类 in = out.getInnerInstance();
- (4)通过内部类对象调用它的成员
- in.成员
- 面试题
- 如何继承非静态成员的内部类
- 示例
class Outer{
class Inner{
}
}
class Other extends Outer.Inner{
Other(Outer out){
out.super();
}
}
- 局部
- 有名字的局部内部类,通常称为局部内部类
- 格式
- [修饰符] class 外部类{
[修饰符] 返回值类型 方法名([形参列表]){
[修饰符] class 内部类{
}
}
}
- 修饰符的问题
- (1)权限修饰符
- 都不行
- (2)static
- 没有
- (3)final(极少)
- 可以
- 表示不能被继承
- (4)abstract(极少)
- 可以
- 表示可以包含抽象方法,需要子类继承
- 有名字的局部内部类的成员
- 除了静态成员,其他都可以
- 使用
- (1)在内部类中使用外部类的成员
- 受所在方法的约束,如果所在方法是静态的,那么只能使用外部类的静态成员,如果所在方法是非静态的,那么都可以使用
- (2)在内部类中使用外部类的局部变量
- 必须是final修饰
- JDK1.8之前,必须显式声明
- JDK1.8之后,默认就是final修饰
- (3)在外部类中使用内部类
- 只能在声明它的方法中使用,而且在声明之后使用
- 和局部变量的作用域一样
- (4)在外部类的外面
- 不可以
- (5)在外部类的其他方法中
- 不可以
- 匿名内部类
- 格式
- new 父类/父接口(){
方法
}
- 修饰符
- 一个都没有
- 匿名内部类的成员
- 除了非静态的都可以,但是一般很少自定义方法等成员,它的成员都是重写父类的,父接口的方法
- 匿名内部类的特点
- (1)声明类和创建对象同时进行, 只有一个对象
public static void main(String[] args) {
//Object的一个子类对象
new Object(){
public void test(){
System.out.println(this.getClass());
}
}.test();
//Object的另一个子类对象
new Object(){
public void test(){
System.out.println(this.getClass());
}
}.test();
}
- (2)子类一定会调用父类的构造器
class MyClass{
private String info;
MyClass(String info){
this.info = info;
}
}
//创建一个MyClass的子类对象,使用匿名内部类
MyClass m = new MyClass("参数"){
};
- 匿名内部类的使用形式
- 形式一
- 匿名内部类的匿名对象直接调用方法
new Object(){
public void test(){
System.out.println(this.getClass());
}
}.test();
- 形式二
- 与父类或父接口构成多态引用
class MyClass{
public void test(){
System.out.println("父类的测试方法");
}
}
MyClass m = new MyClass(){
public void test(){
System.out.println("重写");
}
};
m.test();
- 形式三
- 匿名内部类的匿名对象作为实参
MyClass[] arr = new MyClass[5];
Arrays.sort(arr, new Comparator(){
@Override
public int compare(Object o1, Object o2) {
return 0;
}
});
- 使用其他要求
- (1)在内部类中使用外部类的成员
- 受所在方法的约束,如果所在方法是静态的,那么只能使用外部类的静态成员,如果所在方法是非静态的,那么都可以使用
- (2)在内部类中使用外部类的局部变量
- 必须是final修饰
- JDK1.8之前,必须显式声明
- JDK1.8之后,默认就是final修饰
3.4 (4)类的声明格式
-
格式
- [修饰符] class 类名{ //属性列表 //构造器列表 //get/set方法 //其他方法 }
3.5 (5)如何创建对象
-
new 类名()
- 用无参构造
-
new 类名(实参列表)
- 用有参构造
-
匿名对象和有名对象
-
Student stu = new Student();
- stu对象名,也可以称为对象的引用
-
匿名对象
- System.out.println(new Student());
-
-
对象的内存图
4 、面向对象的基本特征
4.1 封装
-
封装的作用
-
安全
-
使用方便
- 对于使用者屏蔽实现细节
-
-
概念
-
狭义
-
属性的封装
- (1)属性私有化:private
- (2)提供公共get/set方法
-
-
广义
- 方法
- 类
- 包
- 组件
- 系统
-
4.2 继承
-
什么情况下需要继承?继承的好处是什么?
-
为了代码重用
- (1)当有一个父类,如果再声明类时,发现这些类与已经存在的父类有很多相同特征,那么就可以通过继承的方式来简化代码
- (2)已经很多类,发现这些类有很多共同的特点,那么我们可以把这些共同的特点抽取到一个父类中,以便简化代码
-
逻辑的角度
- 表示is-a的关系
-
-
如何继承
- 语法格式: [修饰符] class 子类名 extends 父类名{ }
-
继承后对几个成员的影响
-
属性
-
(1)子类继承父类时,一定会继承父类的所有的属性,包括私有的,但是由于私有的关键字private的原因,在子类中无法直接操作它,但是可以通过get/set方式操作它
-
(2)当子类的属性与父类的属性重名时,而且父类的属性没有私有化,如果要访问父类的属性那么通过super.属性进行访问,如果子类中没有通过super.属性访问,那这个属性就表示是子类自己的
-
面试题
package com.atguigu.review;
public class Test {
public static void main(String[] args) {
Student stu = new Student(); System.out.println(stu.getInfo());//结果? 年龄:10 System.out.println(stu.getAge());//结果?20 如果子类重写,答案是10
}
}
class Person{
int age = 20;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class Student extends Person{
int age = 10;
/*public int getAge(){
return age;
}*/
public String getInfo(){
return "年龄:" + age;
}
}
-
-
-
方法
- (1)子类继承父类时,一定会继承父类的所有的方法,包括私有的,但是由于private,在子类中无法直接操作,但是可以间接操作
- (2)当父类的方法实现不适用于子类时,子类可以对父类的方法的进行重写
-
构造器
-
(1)子类继承父类时,不会继承父类的构造器
-
(2)子类继承父类时,一定会调用父类的构造器
- 如果父类有无参构造,那么子类会默认去调用父类的无参构造 如果父类没有无参构造,只有有参构造,那么子类必须在子类构造器中手动调用父类的有参构造
- 调用父类的无参构造的语句:super(); 调用父类的有参构造的语句:super(实参列表); 而且这两个语句必须在子类的构造器的首行。
-
-
-
继承的原则
-
(1)单继承
- 在Java中只支持单继承,也就是说一个类只能有一个直接父类 –》一个唯一的亲生父亲
-
(2)多层继承
-
在Java中父类还可以有父类,而且在子类中会继承父类以及父类的父类的所有的属性与方法 –》代代相传
- 子类对象在寻找一个方法、属性时,如果本类中找不到,会去直接父类中查找,如果直接父类中也找不到,在往上找,找到为止,一直追溯到java.lang.Object根父类中
- 通过super.属性和方法时,先从直接父类中查找,如果没有,再往上找,直到找到为止,一直可以到java.lang.Object
-
-
(3)一个类可以有很多个子类,子类还可以有子类
- 子孙满堂
- 开枝散叶
-
4.3 多态
-
多态的表现形式
-
(1)方法的重载:同一个类中,功能多种实现形式 方法的重写:父子类中,功能的不同实现形式
-
(2)对象的多态性
-
编译时类型与运行时的类型不一致,编译时看“左边”,运行时看“右边”, 编译时从“父类”中寻找方法,运行时执行的是“子类”重写过的代码
-
对象的多态性的前提: (1)继承 (2)方法的重写 (3)多态引用
-
多态引用
- Person p = new Student();
-
本态引用
- Person p = new Person();
- Student s = new Student();
-
-
-
-
多态的应用
- (1)多态参数
- (2)多态数组
-
类型的转换
-
向上转型
- 子类的对象赋值给父类的变量
- 自动完成
-
向下转型
-
把父类的变量赋值给子类的变量
-
强制类型转换
-
如果想要向下转型成功
- 父类的变量本身指向的就是该子类的对象
-
如何避免ClassCastException
-
在向下转型之前,加判断
- if(变量 instanceof 子类类型){ 子类类型 temp = (子类类型)变量; }
-
-
什么情况下需要向下转型
- 因为一个对一旦向上转型后,那么就无法访问该子类对象中特有的方法,只能访问父类有的方法
- 如果需要通过该对象,访问子类的特有的方法等,那么就需要向下转型
-
-
5 、关键字
5.1 class
- 声明类
5.2 new
- 创建实例,创建对象
- 在堆中申请一块空间
- 只要new就创建新的对象
- new后面一定是构造器
5.3 this
-
当前对象
- (1)如果在构造器中,表示正在被创建的那个对象 (2)如果在其他方法中,表示调用该方法的那个对象
-
使用
-
(1)this.属性
- 当成员变量(属性名)与局部变量(形参)重名时,使用this.属性进行区别
-
(2)this.方法
- 表示调用“当前类”的方法
- 如果子类继承了父类,子类没有重写父类的方法,this.方法也可能是从父类继承的方法
- 如果子类继承了父类,子类重写父类的方法,this.方法就代表子类重写过的代码
-
(3)this()或this(实参列表)
- 表示调用本类的其他构造器,而且必须在构造器的首行
-
5.4 super
-
父类引用
-
使用
-
(1)super.属性
- 当子类的属性与父类的属性重名时,而且父类的属性没有私有化 如果需要调用父类的属性,那么通过super.属性进行区别
-
(2)super.方法
- 当子类的方法重写了父类的方法时, 如果需要调用父类的被重写的方法,那么通过super.方法进行调用
-
(3)super()或super(实参列表)
- 当子类需要调用父类的构造器时,通过super()或super(实参列表)进行调用
-
调用父类的无参构造的语句:super(); 调用父类的有参构造的语句:super(实参列表); 而且这两个语句必须在子类的构造器的首行。
5.5 权限修饰符
- 三个单词,四种形式: public;公共的,范围:任意位置,可以修饰类、成员 protected:受保护的,范围:本包或子类中,可以修饰成员 缺省:默认的,范围:本包,可以修饰类、成员 private:私有的,范围:本类中,可以修饰成员
5.6 static
-
静态的
-
可以修饰成员
-
(1)属性
- 这个属性就称为类变量,它的值是所有对象共享的,存储在方法区 它的get/set方法也是静态的
-
(2)方法
- 这个方法就称为类方法,调用它不需要创建对象,直接可以通过”类名.方法“调用
-
(3)代码块
- 用static修饰的代码块称为静态代码块。 随着类的加载并初始时而执行,而且一个类的静态代码块只执行一次 为静态变量赋值,如果静态变量有显式初始化和静态代码块初始化,它俩属于同级,谁在前谁先执行
-
(4)内部类
5.7 final
-
最终的
-
可以修饰
-
(1)类
- 这个类不能被继承,俗称“太监类”
-
(2)方法
- 这个方法不能被重写,像“圣旨”
-
(3)变量
-
成员变量
-
常量
- 值不能被修改
-
必须手动初始化
-
示例
package com.atguigu.review;
public class TestFinal {
}
class Human{
// private static final String country = “中国”;
private static final String country;
static{
country = "中国";
}
}
class Person{
// final String country = “中国”;
private final String country;
private String name;
/* {
country = "中国";
}*/
Person(){
country = "中国";
}
public Person(String name) {
super(); country = "中国"; this.name = name;
}
}
-
-
-
局部变量
-
常量
- 值不能被修改
-
必须手动初始化
-
-
-
5.8 native
-
原生的
-
可以修饰
-
方法
- (1)表示这个方法的方法体是非Java语言实现
- (2)对于使用这个方法者来说,和普通的Java 方法一样使用
- (3)如果有需要,也可以进行重写
-
6 、包
6.1 包的作用
- (1)避免类的重名 (2)访问权限的控制 (3)便于管理
6.2 如何声明包
-
package 包;
-
要求
- 必须在源文件的首行,一个源文件只能有一句
- 遵循命名规范,所有字母都小写,单词之间使用.,一般以公司的域名倒置
6.3 如何使用其他包的类
-
需要import 包.类名;
-
要求
- 在package和class声明之间,可以多句
- 被使用的类必须是public 或 protected(父子类)
-
形式
-
一一列举
- import java.util.Random; import java.util.Scanner;
-
某个包的类
- import java.util.*;
-
静态导入
- import static java.lang.Math.*;
- System.out.println(PI); System.out.println(sqrt(4));
-
7 Overload和Override的区别
7.1 Overload:方法的重载
在同一类,方法名称相同,形参列表不同的两个或多个方法称为重载。
Override:方法的重写 在子类继承父类时,如果父类的方法实现不适用于子类,子类就可以对父类的方法进行重写,覆盖。