面向对象(OOP)
什么是面向对象
面向对象的思想
- 物以类聚,分类的思维模式,思考问题首先思考解决问题需要哪些分类,然后对各类分别思考。
- 面向对象适合处理复杂的问题,适合处理需要多人协作的问题。
面向对象编程的本质:以类的方式组织代码,以对象的组织(封装)数据
三大特性:
- 封装
- 继承
- 多态
类和对象的关系
- 类是一种抽象的模版。
- 对象是类中的一个实例化后的具体实例。
例:类:人 对象:乔峰大侠
构造器
注意:
- 使用new关键字时,本质是在调用构造器。
- 有参构造:一旦定义了一个有参构造,无参构造就必须显示定义。
- alt + insert 快速生成构造器。
package com.paial.demo01;
public class Student {
String name;
//无参构造方法
//如果没有定义构造方法,系统会自动提供一个无参构造方法
//如果定义了构造方法,系统不会自动提供无参构造方法,需要自行定义
public Student() {
}
//有参构造方法
public Student(String name) {
this.name = name;
}
//没有返回类型,也不能写void
}
封装
属性私有,get/set
追求:高内聚,低耦合
private:私有。
get/set:提供一些可以操作这个属性的方法。
package com.paial.Dame02;
/*
1.提高程序的安全性
2.隐藏代码的实现细节
3.统一接口
4.系统可维护性增强
*/
public class Student {
private String name;
private int age;
//get:获得对象的属性
public String getName(){
return name;
}
//set:设置对象的属性
public void setName(String name){
this.name = name;
}
//alt + insert 快捷键
}
继承
本质:对某一批类的抽象
关键字:extends
相当于父子关系
子类继承了父类就会拥有父类的全部方法(私有的无法被继承)。
ctrl + h:看类之间的关系
注意:一个子类只能有一个父类(一个儿子只有一个父亲,一个父亲可以有多个儿子)
super注意点
- super调用父类的构造方法,必须在构造方法的第一个
- super必须只能出现在子类的方法或者构造方法中
- super和this不能同时调用构造方法!
与this对比:
- 代表的对象不同
- this:本身调用者的这个对象
- super:代表父类对象的使用
- 前提:
- this:没有继承可以使用
- super:只有继承父类后才能使用
- 构造方法
- this():本类的构造
- super():父类的构造
方法的重写
需要有继承关系,子类重写父类的方法!
- 方法名必须相同
- 参数列表必须相同
- 修饰符:范围可以扩大但不能缩小:public>protected>default>private
- 抛出的异常:范围可以缩小但不能扩大:ClassNorFoundException(小) -> Exception(大)
即:子类的方法必须和父类必要一致,方法体不同;
为什么需要重写?
- 父类的功能,子类不一定需要,或者不一定满足!
- Alt + Insert : override;
package com.paial.Demo03;
public class Person {
public void print(){
System.out.println("Person");
}
}
package com.paial.Demo03;
public class Student extends Person{
//对父类方法的重写
@Override
public void print() {
System.out.println("Student");
}
}
package com.paial.Demo03;
public class Application {
public static void main(String[] args) {
Person p = new Student();
p.print();
}
}
多态
注意:
-
多态是方法的多态,属性没有多态
-
存在条件:继承关系,子类方法需要重写,父类引用指向子类
Father f = new Son();
子类重写了父类的方法,执行子类的方法。
-
不能被重写的方法:
- static方法:作用范围只在类之中,属于类
- final 常量
- private方法:私有的方法,不能被继承,自然也就无法重写
对象能执行哪些方法,主要看对象左边的类型,和右边关系不大。
package com.paial.demo04;
public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确定的
//new Student()的实际类型就是Student
//new Person()的类型是Person
//可以指向的引用类型就不确定了,编译看左边,运行看右边
//父类的引用指向子类
//Student 能调用的方法都是自己的或者继承父类的
Student s1 = new Student();
//Person 可以指向子类,但是不能调用子类独有的方法
Person s2 = new Student();
//对象能执行哪些方法,主要看对象左边的类型,和右边关系不大
s1.eat();
s2.run();//子类重写了父类的方法,执行子类的方法
((Student) s2).eat();
}
}
instanceof(类型转换)
左边是对象,右边是类
当对象是右边类或子类的创建对象是返回true,否则false。
package com.paial.demo05;
public class Application {
//Object > Person > Student
//Object > Person > Teacher
public static void main(String[] args) {
Person p = new Student();
Object o = new Student();
System.out.println(p instanceof Student);
System.out.println(p instanceof Object);
System.out.println(p instanceof Teacher);
System.out.println(o instanceof Student);
System.out.println(o instanceof Person);
System.out.println(o instanceof Teacher);
}
}
- 父类引用指向子类的对象
- 把子类转化为父类:向上转型,可能会有方法的丢失
- 把父类转化为子类:向下转型,强制转换
- **目的:**方便方法的调用,减少重复代码!
static详解
代码块:
package com.paial.demo06;
public class Student {
//匿名代码块
//可以用于给类中的成员变量进行初始化赋值
{
System.out.println("匿名代码块执行了");
}
//静态代码块,只执行一次
static {
System.out.println("静态代码块执行了");
}
//构造方法
public Student(){
System.out.println("构造方法执行了");
}
public static void main(String[] args) {
Student s1 = new Student();
System.out.println("==============");
Student s2 = new Student();
}
}
/*
输出:
静态代码块执行了
匿名代码块执行了
构造方法执行了
==============
匿名代码块执行了
构造方法执行了
*/
抽象类
**关键字:**abstract
**抽象方法:**只声明不给出方法具体的实现,子类来实现具体的方法。
抽象类的所有子类都要重写抽象类里的方法,除非子类也是抽象类!
注意:
- 不能new抽象类,只能用子类实现
- 抽象类里面可以写普通方法
- 抽象方法必须在抽象类中
存在的意义?
把相同属性和方法的组件抽象,有利于代码和程序的维护!
接口
**关键字:**interface
制定了一个规则约束,必须遵守
接口都需要有一个实现类(UserServiceImpl)关键字:implements
作用:
- 约束
- 定义一些方法,让不同的人实现
- 所有方法都是public abstract
- 所有变量 public static final
- 接口不能被实例化,接口没有构造方法
- 实现类中必须重写接口中的方法
- 可以多继承,一个实现类继承多个接口
package com.paial.demo08;
public interface UserService {
void run();
void eat();
void sleep();
void study();
}
package com.paial.demo08;
public class UserServiceImpl implements UserService{
@Override
public void run() {
System.out.println("run");
}
@Override
public void eat() {
System.out.println("eat");
}
@Override
public void sleep() {
System.out.println("sleep");
}
@Override
public void study() {
System.out.println("study");
}
}
内部类
**定义:**在一个类的内部在定义一个类
package com.paial.demo07;
public class Test {
private int id = 100;
public void out(){
System.out.println("外部类的方法");
}
//内部类可以使用外部类的方法并且访问私有变量
public class Inner{
public void in(){
System.out.println("内部类的方法");
System.out.println(id);
out();
}
}
}
package com.paial.demo07;
public class Application {
public static void main(String[] args) {
Test outer = new Test();
//通过外部类来实例内部类
Test.Inner inner = outer.new Inner();
inner.in();
}
}