java 面向对象
面向对象(Object Oriented Programming OOP)
初识面向对象
以类的方式组织代码,以对象的组织封装数据。
对象的创建分析
对象的创建必须通过 new 方法实现。
new 方法的本质就是调用构造器。
构造器
作用:
- 初始化对象
规则:
- 必须和类同名
- 没有返回值
**注意点:**当定义有参构造器后,若想使用无参构造器,则必须进行显式定义一个无参构造器。
public class student{
String name; // 属性
// 若不定义构造器,则会默认有一个无参构造器
public student(){ // 无参构造器
}
public student(String name){ // 有参构造器
this.name = name;
}
}
// IDEA 中可以使用 Alt + Insert 快捷键创建构造器
面向对象三大特性
封装
程序设计中追求“高内聚,低耦合”,高内聚是指类的内部数据操作细节由自己来完成,不允许外部干涉;低耦合是指仅仅暴露少量的方法供外部使用。
简单来说就是“属性私有,get/set”
// Pet 类
public class Pet {
// 测试 java 封装特性
// 属性私有: private
private String name;
// get/set : 快捷键 Alt + Insert
// 也可选中 Code 选项卡中的 Generate 选项,选择Getter and Setter
// 无参构造器
public Pet() {
}
// 有参构造器,当定义了有参构造器后,想调用无参构造器必须显示定义无参构造器
public Pet(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
// 主程序,测试 Pet 类
public class Demo1 {
public static void main(String[] args) {
Pet p1 = new Pet();
System.out.println(p1.getName());
Pet p2 = new Pet("旺财");
System.out.println(p2.getName());
}
}
封装的作用
- 提高了系统的安全性,保护数据
- 隐藏了实现细节
- 统一接口
- 增强了系统的可维护性
继承
java 中只有单继承,没有多继承
当多个类存在相同属性和行为时,可将这些内容抽取到单独一个类中,则多个类无需再定义这些属性和行为,只需要继承该类即可。被继承的类称之为父类,继承的类称之为子类。关键字 extends
public class Dog extends Pet{
// Pet 为父类, Dog 为子类
// 子类可直接访问父类中的 非私有 的属性和方法
}
继承的作用
- 提高了代码的复用性
- 使得类与类之间产生了关系,是多态的前提
注意事项
只有当类之间存在着 is a 的关系时,考虑使用继承。不要为了继承部分 功能,而去使用继承。
super 和 this 的区别
- 代表的对象不同,super关键字,代表父类的存储空间标识,是父类的引用;this 关键字代表对象的应用(谁调用就代表谁。
- 使用场景不同,当子父类出现同名成员时,可以用 super 进行区分;当子类要调用父类构造函数时,可以使用super语句。
注意事项
当子类对象初始化时,默认在子类的构造函数第一行调用了super()。
// Dog 类 继承 Pet 类
public class Dog extends Pet{
private int age;
// 当使用 ALt + Insert 快捷键生成子类的构造器时,会先提示选择父类的构造器,再选择子类的。
public Dog(String name, int age) {
super(name);
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class Demo1 {
public static void main(String[] args) {
Pet p1 = new Pet();
System.out.println(p1.getName());
// 父类引用可以指向子类对象
Pet p2 = new Dog("大花",3);
// 但由于父类中没有 getAge(),故此处报错
// 能调用什么方法和左边有关,和右边没有关系。
System.out.println(p2.getAge());
}
}
扩展
IDEA 中在类中使用快捷键 Ctrl + H 可看到类的继承关系树
方法的重写
子类中出现和父类一模一样的方法时(返回值类型,方法名,参数列表都要相同),会出现覆盖操作,称之为重写。
注意事项
- 父类的私有方法,子类看不到,因此父类的私有方法不存在重写。
- 重写时,子类方法的权限一定要大于等于父类方法权限。public >protected >default >private
- 抛出的异常:范围可以缩小,不能被扩大。
- 重写用在子类需要父类的功能,同时又有自己特有的内容时。
- 静态方法只跟类有关,不存在重写。
子父类构造方法的用法
- 在初始化子类对象时,首先执行父类的初始化动作,但不会初始化一个父类对象,子类的构造方法中默认有一个super()。
- 如果父类没有无参构造方法,则可使用super调用父类的有参构造方法(推荐方式)
- 也可使用 this 调用本身的其他构造。this() 和 super() 都是在构造函数的第一行,不能同时出现。
静态代码块、构造代码块,构造方法的执行顺序
父类静态代码块->子类静态代码块->父类构造代码块->父类构造方法->子类构造代码块->子类构造方法
static{
// 静态代码块,类加载时执行一次
}
{
//构造代码块,每次对象实例化时调用一次,
}
多态
定义
对象在不同时刻表现出来的不同状态
多态的前提
- 要有继承(类)或实现(接口)关系
- 要有方法的重写
- 要有父类引用指向子类对象
在程序中的体现
父类或接口的引用指向或者接收自己的子类对象
多态的作用
提高了程序的扩展性和可维护性
多态的弊端
父类调用的时候只能调用父类中的方法,不能调用子类中特有的方法,因为并不清楚哪个子类会继承该父类。
多态成员的特点
- 变量:编译和运行都看等号左边
- 方法:编译看左边,运行看右边
- 静态方法:编译和运行都看左边
不能将父类对象转换为子类类型
父类的引用指向子类对象,该引用可以被提升,可以强制转换。
多态中变化的是子类对象。
// Pet 父类 Dog 子类
{ // 正确
Pet pet = new Dog(); // 父类引用指向子类对象,向上提升
Dog d1 = (Dog)pet; // 向下转换
}
{ // 错误
Pet pet = new Pet()
Dog d1 = (Dog)pet; // 父类对象不能转换
}
抽象类和接口
抽象类
Java 中可以定义没有方法体的方法,该方法的具体实现由子类完成,这种方法称之为抽象方法,包含抽象方法的类必须定义为抽象类。
抽象类中也可以由正常的方法定义。
应用场景
多个对象具有相同的功能,但功能的具体内容有所不同,在抽象的过程中,只抽象功能定义,不抽象功能主体,即只有功能声明,没有功能主体。
注意点
-
抽象类和抽象方法必须被 abstract 关键字修饰
-
抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类。
-
抽象类不能使用 new 方法创建对象,但有构造函数,所有类中都有构造函数
-
抽象类中的抽象方法要被使用,必须通过子类实现,然后通过子类对象调用。
-
若一个类继承了抽象类,则该类要么为抽象类,要么实现了所继承类的所有抽象方法。
public abstract class abstract_demo { // 抽象类 public abstract void say(); //抽象方法 public void shout(){ System.out.println("汪汪"); } }
当写一个类继承该抽象类时,IDEA会自动提示重写里面所有的抽象方法。
接口
接口本质上是一种特殊的抽象类,只包含常量和方法的定义,没有变量和方法的实现。使用关键字 interface 定义
特点
- 不能被示例化
- 没有构造方法
- 一个类如果实现了接口,要么是抽象类,要么实现了接口中的所有方法
- 能被类实现(implement),class 类名 implements 接口名(可多个){}
- 类与接口之间是实现关系,接口与接口之间是继承关系,并且接口可以多继承,一个类也可以实现多个接口。还可以在继承一个类的同时实现多个接口 (className) extends (className) implements (interface1,interface2)
- 接口中成员修饰符是固定的,成员常量:public static final ,成员方法:public abstract ,且可以省略。(推荐 手动给出修饰符)
接口的思想
- 接口是对外暴露的规则
- 接口是程序的功能扩展
- 接口的出现降低了耦合性(实现模块化开发,每个人实现对应的接口即可,提高了开发效率)
- 一个类可以实现多个接口
- 多个类也可以实现同一个接口
public interface interface_demo { public abstract void say(); }
内部类
内部类
将一个类定义在另外一个类里面,里面的类称之为内部类。
特点
- 内部类是外部类的一个成员,所以内部类可直接访问外部类的成员,包括私有成员。
- 内部类仍是一个独立的类,会编译成独立的class文件,但会在前面冠以外部类的类名和$符号。
分类
-
成员内部类
- 定义在类中方法外的类
- 创建对象的格式为:外部类名.内部类名 对象名 = 外部类对象.内部类对象;
-
静态内部类
-
成员内部类加上静态修饰符
-
内部类静态成员,可创建对象访问,也可以直接访问,非静态成员,必须通过创建对象访问。
-
-
局部内部类
- 定义在方法中的类
- 只能在定义的方法内实例化
- 不能使用定义的方法中非final局部变量
- 静态方法中的方法内部类只能访问外部的静态成员
-
匿名内部类
实现一个带内容的外部类或接口的子类匿名对象
格式:new 外部类名或接口名{}
一个 java 文件中可以有多个类但只能有一个 public 类
public class test{ public static void main(String[] args) { // 没有名字初始化类 new Apple().say(); // 这就是一个匿名内部类 new interface1(){ // 相当一个实现接口的类 @Override public void shout() { } }; } } class Apple{ public void say(){ System.out.println("这是一个苹果"); } } interface interface1{ public abstract void shout(); }