OOP
源自视频课程的本人总结,推荐课程链接
初识面向对象
面向过程&面向对象
面向过程:线性思维,方法的每一步
面向对象:分类思维,分类思考,多人协作
描述复杂事物时,从宏观把握,从整体上合理分析,需要使用面向对象思路分析。但是,具体到微观操作,仍需面向过程的思路处理。
面向对象
- 本质:以类的方式组织代码,以对象的组织(封装)数据;
- 三大特性:封装、继承、多肽;
- 对象是具体的事物,类是抽象的,是对对象的抽象;
- 从代码运行的角度考虑是先有类后有对象。
方法回顾和加深
方法的定义
- 格式:修饰符 返回类型 方法名 (参数列表)
- break和return的区别:break跳出switch,结束循环;return结束方法
- 方法名命名规则,见名知意
- 抛出异常
方法的调用
- 类方法调用
- 非静态类方法调用,实例化对象:对象类型 对象名 = 对象值
- 静态类方法调用,添加修饰符static
- static和类一起加载,非静态方法需要类实例化之后才存在
package com.OOP.demo01; public class Demo01 { //和类一起加载的 public static void a(){ // b(); //错误 } //实例化后才存在的 public void b(){ } }
- 非静态类方法调用,实例化对象:对象类型 对象名 = 对象值
- 形参和实参
- 值传递和引用传递
- 值传递
package com.OOP.demo01; public class Demo02 { public static void main(String[] args) { int a = 1; System.out.println(a); //1 Demo02.change(a); //传递的是值,方法中未返回值 System.out.println(a); //1 } //返回值为空 public static void change(int a){ a = 10; } }
- 引用传递
package com.OOP.demo01; //引用传递:对象,本质还是值传递 public class Demo03 { public static void main(String[] args) { Person person = new Person(); //类实例化 System.out.println(person.name); //null Demo03.change(person); System.out.println(person.name); //ada ? 改变了对象的值 } public static void change(Person person){ person.name = "ada"; } } //定义一个Person类,有一个属性:name class Person{ String name; //默认null }
对象的创建分析
- 创建一个Student类
package com.OOP.demo02;
//学生类
public class Student {
//属性:字段
String name; //默认null
int age; //默认0
//方法
public void study(){
System.out.println(this.name+"在学习");
}
}
- 实例化类,返回一个对象(创建一个对象)
package com.OOP.demo02;
//一个项目应该只存在一个main()方法
public class Application {
public static void main(String[] args) {
//类是抽象的
//类实例化返回一个自己的对象
//xiaoming对象就是Student类的一个具体实例
Student xiaoming = new Student();
Student xh = new Student();
//赋值
xiaoming.name = "小明";
xiaoming.age = 10;
xh.name = "小红";
xh.age = 20;
System.out.println(xiaoming.name);
System.out.println(xiaoming.age);
System.out.println(xh.name);
System.out.println(xh.age);
}
}
类的构造器
- 特点:①必须和类的名字相同;②必须没有返回类型,也不能写void
- 类构造器分为有参和无参两种;当没有有参构造器时,类中默认有一个无参构造器;当类中有一个或几个有参构造器时,如果想使用无参构造器必须显示定义一个无参的构造,否则new实例化时,类中要有参数,不然报错。
- new本质是在调用构造方法;初始化对象的值
- 快捷键:Alt+Insert—构造器(有参或无参)
- this.name = name; 前一个name指的是属性,后一个name指的是赋值
- 构造器
package com.OOP.demo02; public class Person { //一个类即使什么都不写,它也存在一个方法-构造方法 //构造方法(不能有返回类型或void,必须与类名一致) public Person(){ } String name; int age; //构造方法分为有参和无参 //当类中有有参构造器时,若想保留无参构造器,则必须显示地写出无参构造器 //有参构造器 public Person(String name, int age){ this.name = name; this.age = age; } }
- main测试
package com.OOP.demo02; //一个项目应该只存在一个main()方法 public class Application { public static void main(String[] args) { //new实例化 Person person = new Person(); person.name = "asd"; System.out.println(person.name); } }
创建对象的内存分析
代码对比分析
实例化同一个类Pet()的两个对象dog、cat,而内存中对象作为引用变量分别创建对象类
总结类与对象
- 类与对象
类是一个模版,抽象的;对象是具体的实例; - 方法的定义与调用 修饰符 返回类型 方法名(参数列表){}
- 对象的引用:引用类型,基本类型(8);对象是通过引用实现操作,引用指向的是地址;
- 属性,字段
- 默认值:int ->0;String -->null;char–>u0000;boolean–>false; 引用–>null
- 对象的创建和使用
- 使用new创建对象,构造器(类名和方法名同);Person person = new Person()
- 对象的属性 person.name
- 对象的方法 person.sleep()
- 类
- 静态的属性 属性
- 动态的行为 方法
面向对象三大特性
封装
- 特点:高内聚,低耦合;
- 高内聚就是类的内部数据操作细节自己完成,不允许外部干涉
- 低耦合,仅暴露 少量的方法给外部使用
- 封装关键字:private
- 封装的作用:
- 提高程序的安全性,保护数据
- 隐藏代码实现细节
- 统一接口
- 易于维护系统
- 代码示例:
- 封装类
package com.OOP.demo04; public class Student { //封装:属性私有private private String name; private String sex; private int age; //定义get、set供外面访问 public String getName() { return this.name; } public void setName(String name){ this.name = name; } // Alt + Insert 自动生成所有属性的get、set public String getSex() { return sex; } public int getAge() { return age; } public void setSex(String sex) { this.sex = sex; } //保证数据安全性 public void setAge(int age) { if (age>120 || age <= 0){ this.age = 3; }else{ this.age = age; } } }
- main测试
package com.OOP.demo02; import com.OOP.demo04.Student; //一个项目应该只存在一个main()方法 public class Application { public static void main(String[] args) { //实例化对象 Student student = new Student(); student.setName("小明"); student.setAge(9999); //不合法 System.out.println(student.getName()); //小明 System.out.println(student.getAge()); //3 } }
继承
- 继承的本质就是对某一批类的抽象
- 继承:extends表示“扩展”。子类就是父类的扩展;父类私有属性和方法无法被子类继承
- Java中类只有单继承,没有多继承;即每个子类只能有一个父类
- 类与类之间的关系有:继承、依赖、组合、聚合等
- object类:理论上,所有的类都继承于object类
示例:- 对比效果(源码粘在下面)
- 父类-Person
package com.OOP.demo05; public class Person { //方法 public void shout(){ System.out.println("你说话了!"); } }
- 子类-Student
package com.OOP.demo05; public class Student extends Person { }
- main测试
package com.OOP.demo02; import com.OOP.demo05.Student; //一个项目应该只存在一个main()方法 public class Application { public static void main(String[] args) { //实例化对象 Student student = new Student(); student.shout(); } }
- 对比效果(源码粘在下面)
继承之Super
- 子类调用父类属性或方法(非private)时,用Super,super只能用在方法或构造方法里;调用本类属性或方法时,用this;**super()和this不能同时用在构造方法里。
A. 示例1对比效果(属性):
源码:
- 父类
package com.OOP.demo05;
public class Person {
protected String name = "kkkk";
}
- 子类
package com.OOP.demo05;
public class Student extends Person {
String name = "abdd";
public void test1(){
System.out.println(name); //abdd
System.out.println(this.name); //abdd
System.out.println(super.name); //kkkk
}
}
- main测试
package com.OOP.demo02;
import com.OOP.demo05.Student;
//一个项目应该只存在一个main()方法
public class Application {
public static void main(String[] args) {
//实例化对象
Student student = new Student();
student.test1();
}
}
B. 示例2对比效果(方法):
源码:
- 父类
package com.OOP.demo05;
public class Person {
public void print(){
System.out.println("Person写!");
}
}
- 子类
package com.OOP.demo05;
public class Student extends Person {
public void print(){
System.out.println("Student写!");
}
public void test2(){
print(); //子类
this.print(); //子类
super.print(); //父类
}
/* 输出结果
Student写!
Student写!
Person写!
*/
}
- main测试
package com.OOP.demo02;
import com.OOP.demo05.Student;
//一个项目应该只存在一个main()方法
public class Application {
public static void main(String[] args) {
//实例化对象
Student student = new Student();
student.test2();
}
}
- 子类的无参构造中,默认调用父类无参构造;super()必须写在构造中的第一行
示例对比效果:
源码:
- 父类
package com.OOP.demo05;
import sun.print.PeekGraphics;
public class Person {
public Person(){
System.out.println("person执行无参!");
}
}
- 子类
package com.OOP.demo05;
public class Student extends Person {
public Student(){
//默认执行了Super()
super(); //super()和this必须写第一行
System.out.println("student执行无参!");
}
/*执行结果
student执行无参!
person执行无参!
*/
}
- main测试
package com.OOP.demo02;
import com.OOP.demo05.Student;
//一个项目应该只存在一个main()方法
public class Application {
public static void main(String[] args) {
//实例化对象
Student student = new Student();
}
}
- this VS super
- 代表的对象不同:
this:本身调用者这个对象
super:代表父类对象的引用 - 前提:
this:没有继承也可以使用
super:只能在继承的条件下菜可以使用 - 构造方法
this():本类的构造
super():父类的构造
- 代表的对象不同:
继承之重写
- 父类和子类中的static类方法调用
A. 效果对比:
B.源码:- 父类
package com.OOP.demo06; public class B { public static void test(){ System.out.println("B==>test"); } }
- 子类
package com.OOP.demo06; public class A extends B { public static void test(){ System.out.println("A==>test"); } }
- main测试
package com.OOP.demo02; import com.OOP.demo06.A; import com.OOP.demo06.B; public class Application { public static void main(String[] args) { //实例化对象 //方法的调用只和左边(数据类型)有关 A a = new A(); a.test(); //A==>test B b = new A(); b.test(); //B==>test } }
- 重写:①继承关系;②子类对父类非静态方法的重写
A.效果对比
B.源码:- 父类
package com.OOP.demo06; public class B { public void test(){ System.out.println("B==>test"); } }
- 子类
package com.OOP.demo06; public class A extends B { @Override //Override 重写 public void test() { super.test(); } }
- main测试
package com.OOP.demo02; import com.OOP.demo06.A; import com.OOP.demo06.B; public class Application { public static void main(String[] args) { //实例化对象 A a = new A(); a.test(); //A==>test //父类的引用指向了子类 B b = new A(); //子类重写了父类的方法 b.test(); //A==>test } }
- 总结
- 重写需要有继承关系,子类重写父类的方法
- 重写方法的子类和父类的方法名必须相同
- 修饰符:范围可以扩大但不能缩小; public>protected>default>private
- 抛出异常:范围可以缩小,但不能扩大; ClassNotFoundException —> Exception(大)
- 重写的作用:父类的功能,子类不一定需要,或者不一定满足;
- Alt+ Insert; override
多态
- 多态是方法的多态,属性没有多态
- 父类和子类要有联系;类型转换异常,ClassCastException
- 多态存在的条件:继承关系、方法需要重写、父类引用指向子类对象;Father f1 = new Son();
- 子类能调用的方法都是自己的或者继承父类的
- 父类可以指向子类,但不能调用子类独有的方法
- 方便方法的调用,较少重复的代码
- 父类->子类,需强制转换;子类 ->父类,自动转换(可以会丢失自己本来的一些方法)
A. 效果对比
B.源码:- 父类
package com.OOP.demo07; public class Person { public void run(){ System.out.println("person run"); } }
- 子类
package com.OOP.demo07; import com.OOP.demo07.Person; public class Student extends Person { @Override public void run() { System.out.println("student run"); } }
- main测试
package com.OOP.demo02; import com.OOP.demo07.Person; import com.OOP.demo07.Student; public class Application { public static void main(String[] args) { //一个对象的实际类型是确定的 //但是它可以指向的引用类型时不确定的:父类引用指向子类 Student s1 = new Student(); Person s2 = new Student(); Object s3 = new Student(); s1.run(); //student run s2.run(); //student run 子类重写了父类方法,执行子类方法 } }
instanceof和类型转换
- instanceof:System.out.println(X instanceof Y) -> (1)X与Y是否存在关系(编译错误);(2)X是否是Y的子类(是true否false)
示例:父类Person,子类Student和Teacher
package com.OOP;
import com.OOP.demo07.Person;
import com.OOP.demo07.Student;
import com.OOP.demo07.Teacher;
public class Application {
public static void main(String[] args) {
//Object -> String
//Object -> Person -> Teacher
//Object -> Person -> Student
Object object = new Student();
System.out.println(object instanceof Student); //True
System.out.println(object instanceof Person); //True
System.out.println(object instanceof Object); //True
System.out.println(object instanceof Teacher); //False
System.out.println(object instanceof String); //False
System.out.println("========================");
//Person与String是同级
Person person = new Student();
System.out.println(person instanceof Student); //True
System.out.println(person instanceof Person); //True
System.out.println(person instanceof Object); //True
System.out.println(person instanceof Teacher); //False
// System.out.println(person instanceof String); //编译错误
System.out.println("==================");
//instanceof比较的是两边有关系的,无关系的会报编译错误
Student student = new Student();
System.out.println(student instanceof Student); //True
System.out.println(student instanceof Person); //True
System.out.println(student instanceof Object); //True
// System.out.println(student instanceof Teacher); //编译错误
// System.out.println(student instanceof String); //编译错误
}
}
- 类型转换:父类(高)、子类(低);低到高自动转换,高到低强制转换
示例:
package com.OOP;
import com.OOP.demo07.Person;
import com.OOP.demo07.Student;
import com.OOP.demo07.Teacher;
public class Application {
public static void main(String[] args) {
Person student = new Student();
//强制类型转换 -> (类型)
((Student) student).go();
}
}
static关键字
- 静态变量或静态方法与类一起加载,且只执行一次
- 静态导入包(不常用,了解)
- final关键字,final修饰的类不能被继承,即无子类
示例1:静态变量
public class Application {
//静态变量
private static int age;
private double score;
public static void main(String[] args) {
Application application = new Application();
System.out.println(application.age);
System.out.println(application.score); //对象调用score
System.out.println(Application.age);
//非静态变量 调用类变量 编译错误;实例化为对象,才可调用
// System.out.println(Application.score);
}
}
示例2:静态方法
public class Application {
public void run(){
go(); //方法里也可以直接调用静态方法
}
public static void go(){
}
public static void main(String[] args) {
// Application.run(); //编译错误,非静态类方法
//实例化后。就可调用非静态方法
Application application = new Application();
application.run();
Application.go(); //静态方法在类定义时就加载了
}
}
示例3:匿名代码块(2)、静态代码块(1)和构造方法(3)
public class Person {
//2
{
System.out.println("匿名代码块");
}
//1,且只执行一次
static {
System.out.println("静态代码块");
}
//3
public Person(){
System.out.println("构造方法");
}
//main
public static void main(String[] args) {
Person person1 = new Person();
System.out.println("=================");
Person person2 = new Person();
/* 运行结果
静态代码块
匿名代码块
构造方法
=================
匿名代码块
构造方法
*/
}
}
示例4:导入包
//静态导入包
import static java.lang.Math.random;
import static java.lang.Math.PI;
public class Test {
public static void main(String[] args) {
System.out.println(random());
System.out.println(PI);
}
}
抽象类和接口
- 抽象类:
- 不能new抽象类,只能靠子类去实现它(约束)
- 抽象类里可以写普通的方法
- 抽象方法必须写在抽象类里
- 继承了含抽象方法的抽象类的子类必须要重写抽象方法,除非子类也是抽象类
//抽象类
public abstract class Action {
//抽象方法,只有方法名,无方法实现,由子类实现override
public abstract void doSomthing();
//构造器方法
public Action(){
System.out.println("抽象类的构造方法!");
}
//普通方法
public void Speak(){
}
}
子类继承实现抽象类中的抽象方法的重写:extends
public class C extends Action{
@Override
public void doSomthing() {
}
}
- 接口:
- 定义接口关键字:interface,接口都需要实现类
- 接口的实现类可以实现多继承
- 接口中的所有方法定义都是抽象的public abstract;常量定义:public static final
- 接口不能被实例化。接口中没有构造方法
- 实现类中用关键字:implements,必须重写接口中定义的所有方法override
- 接口1:
public interface UserService {
//增删改查,省略了public abstract
void add();
void delete();
void update();
void query();
}
- 接口2:
public interface TimeService {
void timer();
}
- 实现类:implements
public class UserServiceImpl implements UserService,TimeService{
@Override
public void timer() {
}
@Override
public void add() {
}
@Override
public void delete() {
}
@Override
public void update() {
}
@Override
public void query() {
}
}