Java面向对象
面向对象编程
Java的核心思想就是OOP
初识面向对象
面向过程&面向对象
-
面向过程思想(框架)
线性思维 适合处理一些比较简单的问题
-
面向对象思想(流程)
物以类聚 分类的思维模式 适合处理需要多人合作的复杂问题
属性+方法 - >类
什么是面向对象
- 面向对象编程(Object-Oriented Programming,OOP)
- 面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据
- 抽象
- 三大特性
- 封装
- 继承
- 多态
回顾方法及加深
方法的定义
-
修饰符
-
返回类型
package com.oop.demo01; public class Demo01 { public static void main(String[] args) { } /* 修饰符 返回值类型 方法名(...){ // 方法体 return 返回值; return结束方法,返回一个结果 } */ public String sayHello() { return "Hello World"; } public void sayHi() { System.out.println("Hi"); return; // 也可以不写return } public int max(int a, int b) { return a > b ? a : b; // 三元运算符 } }
-
break:跳出switch 结束循环 return:结束方法, 返回结果
-
方法名: 驼峰 见名知意
-
参数列表:参数类型,参数名
-
异常抛出:后面讲解 例:数组下标越界:ArrayIndexOutOfBounds
public void readFile(String file) throws IOException{ }
方法的调用
-
静态方法

-
非静态方法

package com.oop.demo01; public class Demo02 { public static void main(String[] args) { //实例化这个类 new //对象类型 对象名字 = 对象值; Student student = new Student(); student.say(); } //static和类一起加载 public static void a() { // b();// 报错 b前面加static 或者 把a前面的static删掉 } //对象在类实例化之后才存在 public void b() { } }
-
形参和实参
package com.oop.demo01; public class Demo03 { public static void main(String[] args) { //实参和形参的类型要对应 int add = Demo03.add(1, 2); //实参 System.out.println(add); } public static int add(int a, int b) { //形参 return a + b; } }
-
值传递和引用传递
package com.oop.demo01; //值传递 public class Demo04 { public static void main(String[] args) { int a = 1; System.out.println(a); Demo04.change(a); System.out.println(a); //结果为1 } //返回值为空 public static void change(int a) { a = 10; } }
package com.oop.demo01; //引用传递:对象 本质还是值传递 public class Demo05 { public static void main(String[] args) { Person person = new Person(); System.out.println(person.name);// null Demo05.change(person); System.out.println(person.name);// Arb } public static void change(Person person) { //person是一个对象,指向的--->Person person = new Person();这是一个具体的人,可以改变属性! person.name = "Arb"; } } //定义了一个Person类,有一个属性:name class Person{ String name; }
-
this关键字
类与对象
类与对象的创建
类是一种抽象的数据类型,它是对某一类事物整体描述/定义,但是并不能代表某一个具体的事物
一个Java类里面可以有多个类,但是只能有一个public class
从本节开始要注意不要在每一个类中都定义一个main方法,可以直接创建一个主启动的class里面用main方法
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) {
//类是抽象的,要把类实例化
//类实例化后会返回一个自己的对象
//对象就是一个Student类的具体实例
Student student1 = new Student();
Student student2 = new Student();
student1.name = "小明";
student1.age = 3;
System.out.println(student1.name);
System.out.println(student1.age);
student2.name = "小红";
student2.age = 3;
System.out.println(student2.name);
System.out.println(student2.age);
}
}
构造器详解(重要)
类中的构造器也称为构造方法
特点:1. 必须和类的名字相同 2.必须没有返回类型,也不能写void
默认的构造器例子
package com.oop.demo02;
public class Person {
//一个类就算什么都不写它也会存在一个方法,这个方法就是构造方法
}
package com.oop.demo02;
public class Application {
public static void main(String[] args) {
//使用new关键字实例化一个对象
Person person = new Person();
}
}
虽然不输出任何东西,但是仍然能运行,就是因为系统提供了一个默认的构造器如下:多了一个无方法体的方法
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.oop.demo02;
public class Person {
public Person() {
}
}
怎么知道默认构造器的内容呢?
- 点击IDEA右上角的设置标志
- 打开Project Structure
- 点击module 添加根目录
- 找到module directory中out文件
- apply后即可在视图中打开out里面所需的class文件
我们也可以自己显式定义构造器
package com.oop.demo02;
public class Person {
//一个类就算什么都不写它也会存在一个方法,这个方法就是构造方法
//显式定义构造器
String name;
//无参构造:实例化初始值
/*
1.使用new关键字,本质是调用构造器
2.用来初始化值
*/
public Person() {
}
//有参构造:一旦定义了有参构造,无参构造就必须显式定义
public Person(String name) {
this.name = name;
}
//快捷键:alt + insert 选择constructor
}
package com.oop.demo02;
public class Application {
public static void main(String[] args) {
//使用new关键字实例化一个对象
Person person = new Person("Arb"); //new的时候有参,调用的就是有参构造器
System.out.println(person.name);
}
}
创建对象内存分析

封装
该暴露的暴露,该隐藏的隐藏 高内聚低耦合
属性私有,get/set
作用:
- 提高程序的安全性,保护数据
- 隐藏代码的实现细节
- 统一接口
- 系统的可维护性增加
package com.oop.demo04;
public class Student {
//属性私有
//名字
private String name;
//学号
private int id;
//性别
private char gender;
//年龄
private int age;
//提供一些可以操作这个属性的方法!
//提供一些public的get/set方法
//get 获得这个数据
public String getName() {
return this.name;
}
//set 给这个数据设置值
public void setName(String name) {
this.name = name;
}
//alt+insert 快速生成get/set
public int getAge() {
return age;
}
public void setAge(int age) {
if(age < 0 || age > 200) {
age = 0;
}
else {
this.age = age;
}
}
}
package com.oop;
import com.oop.demo03.Pet;
import com.oop.demo04.Student;
public class Application {
public static void main(String[] args) {
Student s1 = new Student();//使用ctrl + alt +v 自动补全前面的代码 使用alt+enter可将提示快速显示出来
s1.setName("John");
System.out.println(s1.getName());
s1.setAge(999);
System.out.println(s1.getAge());
}
}
继承
什么是继承
继承的本质是对类的抽象
继承是类与类之间的一种关系
Java中只有单继承没有多继承:一个儿子只有一个爸爸,一个爸爸可以有很多个儿子
package com.oop.demo05;
//人:父类
public class Person {
private int money = 10_000_000;
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public void say() {
System.out.println("说了一句话");
}
}
package com.oop.demo05;
//Student is Person 子类;派生类
//子类继承了父类,就会拥有父类的全部public方法 private无法被继承
//快捷键 ctrl + h 打开树 最高层有一个object类 Java中所有的类都默认直接或间接继承Object类
public class Student extends Person{
}
package com.oop.demo05;
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.say();
student.setMoney(100);
System.out.println(student.getMoney());
}
}
Super详解
package com.oop.demo05;
//人:父类
public class Person {
protected String name = "abc";
public void print() {
System.out.println("Person");
}
//父类构造器 alt+insert
public Person() {
System.out.println("Person无参构造");
}
}
package com.oop.demo05;
public class Student extends Person{
private String name = "def";
public void print() {
System.out.println("Student");
}
public void test(String name) {
System.out.println(name);
//输出传递的name
System.out.println(this.name);
//输出def
System.out.println(super.name);
//输出abc
}
public void test1() {
print(); //student
this.print(); //student
super.print(); //person
}
public Student() {
//有一个隐藏代码:super();自动调用父类构造器,且必须在子类构造器第一行
System.out.println("Student无参构造");
}
}
package com.oop.demo05;
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.test("myName");
student.test1();
}
}
super注意点:
- super调用父类的构造方法,必须在构造方法的第一个
- super必须只能出现在子类的方法或者构造方法中
- super和this不能同时调用构造方法
与this的不同点
代表的对象不同:
this:本身调用这个对象
super:代表父类对象的引用
前提:
this没用继承也能使用
super只能在继承条件才可以使用
构造方法:
this();本类的构造
super();父类的构造
方法的重写
静态static:
package com.oop.demo05;
//重写都是方法的重写,和属性无关
public class B {
public static void test() {
System.out.println("B=>test()");
}
}
package com.oop.demo05;
//继承关系
public class A extends B {
public static void test() {
System.out.println("A=>test()");
}
}
package com.oop.demo05;
public class Application {
public static void main(String[] args) {
//静态方法的调用只和左边定义的数据类型有关
A a = new A();
a.test(); //A类的方法
//父类的引用指向了子类
B b = new A();
b.test(); //B类的方法
}
}
运行结果为:
B => test()
A => test()
非静态:
package com.oop.demo05;
//重写都是方法的重写,和属性无关
public class B {
public void test() {
System.out.println("B=>test()");
}
}
package com.oop.demo05;
//继承关系
public class A extends B {
//override:重写 使用alt+insert 默认调用父类的方法
@Override //注解:有功能的注释
public void test() {
System.out.println("A=>test()");
}
}
package com.oop.demo05;
public class Application {
public static void main(String[] args) {
A a = new A();
a.test(); //A类的方法
//父类的引用指向了子类
B b = new A(); // //子类重写了父类的方法
b.test();
}
}
运行结果:
A=>test()
A=>test()
方法的重写只与非静态的方法有关,不要加static,由上一讲的图示知道static和类一起加载
重写:需要有继承关系,子类重写父类的方法,方法体不同
- 方法名必须相同
- 参数列表必须相同
- 修饰符:范围可以扩大但不能缩小 public > protected > default > private
- 抛出的异常:范围可以被缩小,但不能扩大
无法重写的情况
- static方法,属于类,不属于实例
- final 常量
- private方法
为什么要重写:
父类的功能子类不一定需要,或者不一定满足
多态
package com.oop.demo06;
public class Person {
public void run() {
System.out.println("run");
}
}
package com.oop.demo06;
public class Student extends Person {
}
package com.oop;
import com.oop.demo06.Person;
import com.oop.demo06.Student;
public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确定的
//new Student(); 就是Student new Person(); 就是Person
//可以指向的引用类型就不确定
//同样是student但是有多种引用类型形态 —— 多态
Student s1 = new Student();
Person s2 = new Student(); //父类的引用指向子类的类型
Object s3 = new Student();
s2.run();
s1.run();
}
}
运行结果:
run
run
对Student类run()方法重写
package com.oop.demo06;
public class Student extends Person {
@Override
public void run() {
System.out.println("son runs");
}
}
运行结果:
son runs
son runs
由上一讲我们知道:子类重写了父类的方法,父类执行子类的方法
给Student类多写一个eat方法
package com.oop.demo06;
public class Student extends Person {
@Override
public void run() {
System.out.println("son runs");
}
public void eat() {
System.out.println("eat");
}
}
package com.oop;
import com.oop.demo06.Person;
import com.oop.demo06.Student;
public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确定的
//new Student(); 就是Student new Person(); 就是Person
//可以指向的引用类型就不确定
//同样是student但是有多种引用类型形态 —— 多态
//Student能调用的方法都是自己的或者继承父类的
Student s1 = new Student();
//Person 父类 可以指向子类,但是不能调用子类独有的方法
Person s2 = new Student(); //父类的引用指向子类的类型
Object s3 = new Student();
//对象能执行哪些方法,主要看对象左边的类型,和右边的关系不大
s1.eat(); //能运行eat
s2.eat(); //报错 s2不能调用子类独有的方法 解决方法:((Student)s2).eat(); 大转小
}
}
多态注意事项
- 多态是方法的多态,属性没有多态
- 父类和子类有联系 将狗转换成猫(非父子关系)会出现类型转换问题ClassCastException
- 存在条件:继承关系,方法需要重写,父类引用指向子类对象
instanceof和类型转换
instance0f
package com.oop;
//这几个类里面都没装东西
import com.oop.demo06.Person;
import com.oop.demo06.Student;
import com.oop.demo06.Teacher;
public class Application {
public static void main(String[] args) {
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 不报错是因为object和teacher还有点关系
System.out.println(object instanceof String);
System.out.println("====================================================");
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 不报错是因为person和teacher还有点关系
// System.out.println(person instanceof String); //报错 person和String都是Object下的但是两者没有半毛钱关系直接报错
System.out.println("=======================================================");
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); //编译就报错 同属person下 但是两者互不相干
//System.out.println(X instanceof Y);
//能否编译通过就看x的引用类型是否和Y有父子关系
//true:X的实际new的类型是Y的子类
}
}
类型转换
package com.oop.demo06;
public class Student extends Person {
public void go() {
System.out.println("go");
}
}
package com.oop;
import com.oop.demo06.Person; //空的
import com.oop.demo06.Student; //有go方法
import com.oop.demo06.Teacher; //空的
public class Application {
public static void main(String[] args) {
//类型的转换:如同基本类型的转换 高 ->低:强制转换 低 ->高:自动转换
//高 低
Person a = new Student();
// a.go(); 报错 父类不能执行子类独有的方法 将a的类型强制转换成Student类型就可以使用
Student a1 = (Student) a;
a1.go();
//也可以一步到位
((Student)a).go();
//子类转换成父类
Student b = new Student();
b.go();
Person c = b; //子类自动转换父类
//c.go(); 丢失子类特有的方法
}
}
static关键字
package com.oop.demo07;
//static
public class Student {
private static int age; //静态变量
private double score; //非静态变量
public void run() {
//里面可以调用静态方法
}
public static void go() {
//里面不能调用普通方法 因为static和类一起加载,加载的时候run()还没创建出来
}
public static void main(String[] args) {
Student student = new Student();
System.out.println(Student.age); //Student.age.sout通过类来直接使用age 静态变量适合这样操作
System.out.println(student.age);
System.out.println(student.score);
//System.out.println(Student.score); 报错缺少static
//run(); 直接调用run()报错 要先new Student(); 然后对象.方法();
new Student().run();
Student.go(); //有了static关键字的go()方法调用go很简单
go(); //甚至可以连Student都不要
}
}
package com.oop.demo07;
public final class Person { //person被final修饰 Student不能继承Person
//2.
{
//匿名代码块 也可以赋初始值 不建议这样写
System.out.println("匿名代码块");
}
//1
static {
//静态代码块 用于加载一些初始数据 只执行一次
System.out.println("静态代码块");
}
public Person() {
System.out.println("构造方法");
}
//3.
public static void main(String[] args) {
Person person1 = new Person();
System.out.println(" ============================================ ");
Person person2 = new Person();
}
}
//运行结果:
//静态代码块
//匿名代码块
//构造方法
// ============================================
//匿名代码块
//构造方法
package com.oop.demo07;
//静态导入包
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()); //使用静态导入包就可以不用在random前加Math.
System.out.println(PI); //使用静态导入包直接使用PI
}
}
抽象类
- 不能new这个抽象类,只能靠子类去实现他
- 抽象类里可以写普通方法
- 抽象方法必须写在抽象类中
package com.oop.demo08;
//abstract:抽象类 和之后学习的接口有相似之处 extends单继承 接口可以多继承
public abstract class Action {
//只写一个doSomething框架希望有人帮我完成这个方法
//abstract,抽象方法,只有方法名字,没有方法实现
public abstract void doSomething();
public void run() {
System.out.println("run");
}
}
package com.oop.demo08;
//抽象类的所有方法,继承了他的子类,都必须要重写来实现他的方法 除非他本身也是abstract 这样就要交给他的子子类去实现
public class A extends Action { //提示必须要重写这个方法 alt+insert implement
@Override
public void doSomething() {
}
}
思考
抽象类不能new,那他存在构造器吗?存在
接口
只有规范,无法自己写方法
接口的本质是契约
声明接口的关键字是interface
package com.oop.demo09;
public interface UserService {
//接口中的所有定义的方法都是抽象的 默认是public abstract
void add();
void delete();
void update();
void query();
int age = 99; //属性默认为常量 public static final
}
package com.oop.demo09;
public interface TimeService {
void timer();
}
package com.oop.demo09;
//类可以实现接口,类+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() {
}
}
接口总结
- 约束
- 定义一些方法,让不同的人实现
- 方法:public abstract
- 属性:public static final
- 接口不能被实例化,接口中没有构造方法
- implements可以实现多个接口
- 实现接口必须要重写接口中的方法