面向对象(OOP)
Object-Oriented Programming(oop)
初识面向对象
属性+方法=类
面向过程:顺序思考
面向对象:分类的思维模式,先思考如何分类
面向对象的本质
以类的方式组织代码,以对象的组织(封装)数据
抽象
抽出相像的部分
对象是具体的事务
类是抽象的事物,是对对象的抽象
三大特征
-
封装
把代码封装起来,留一个口,给别人调用
-
继承
子类继承父类的所有对象
-
多态
相同事物会反馈不同的结果
方法的回顾和加深
-
方法的定义
修饰符
返回值类型:return代表结束方法
方法名
参数列表
异常抛出
-
方法的调用
静态方法:
静态方法可以在别的类调用 ,static和类一起加载,因此非静态需要实例化
非静态方法形参和实参:
非静态方法需要实例化
值传递和引用传递:
调用方法只传值进去,不改变原来定义的值
引用传递:
本质还是值传递
this关键字:
当前类和对象
对象的创建分析
构造器也叫构造方法,是创建对象必须调用的,他有两个特点:
构造器的特点
-
必须和类的名字相同
-
必须没有返回类型,也不能写void
构造器的作用
实例化初始值
一旦定义有参构造,无参构造就必须显示
-
new的本质就是调用构造器
package day7; public class Student { String name; //无参构造 // public Student(){ // } public Student(String name) { this.name = name; } public Student() { } //有参构造 // public Student(String name){ // this.name=name; // } }
默认初始值:
-
数字 0 0.0
-
char:u0000
-
boolean:false
-
引用:null
面向对象三大特性
封装
-
该漏的漏,该藏的藏
高内聚,低耦合:
高内聚:就是类的内部数据操作细节自己完成,不允许外部干涉;
低耦合:仅暴露少量的方法给外部使用
-
封装(数据的隐藏)
通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐蔽
属性私有:set/get
-
调高安全性,保护数据
-
隐藏代码的实现细节
-
统一接口
-
维护性增加了
package day7; public class Kid { //属性私有 private String name; private int age; private String sex; private int id; //set get方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public int getAge() { return age; } public void setAge(int age) { if (age>120||age<0){ this.age = 3; }else{ this.age=age; } } }
继承
extands的意思是“扩展”,子类是父类的扩展
JAVA中只有单继承,没有多继承
继承的本质是对某一批类的继承,实现对现实世界更好的建模
继承是类与类之间的关系
所有的类都继承object类
super
super必须在构造器的第一行,先输出父类的构造器,再子类的构造器
父类的构造器必须在子类构造器的第一行
注意:
-
super调用父类的构造方法,必须在构造方法的第一个
-
super必须稚嫩恶搞出现在子类方法或者构造方法的第一个
-
super和this不能同时调用构造方法
this:
代表的对象不同
this:本身调用者这个方法
super:代表父类对象的应用
前提
this:没有继承也可以使用
super:只能在继承条件才可以使用
构造方法
this():本类的构造
super():父类的构造
重写
重写都是方法的重写
子类重写父类的方法
-
方法名必须相同
-
参数列表必须相同
-
修饰符:范围可以扩大不能缩小
-
抛出异常:可以被缩小但不能扩大
重写,子类和父类不许一直,方法体不同
为什么需要重写:
-
父类的功能,子类不一定需要,或者不一定满足
-
ALT+INSERT
多态
父类可以指向子类
/* 一个对象的实际类型是确定的 new Student(); new Person(); 可以指向的引用类型就不确定了:父类的引用指向子类 */ Student s1 = new Student(); Person p1 = new Student(); Object o1 = new Student(); p1.run();//子类重写了父类的方法,执行子类的方法 s1.run();
子类和父类都有相同的方法,调用父类中的方法时,子类没有重写就调用弗雷德方法,子类重写了父类中的方法就调用子类的方法
对象能执行那些方法,主要看对象左边的类型,和右边关系不大
父类可以指向子类,但是不能调用子类独有的方法
注意
-
多态是方法的多态
-
父类和子类有联系,类型转换异常 ClassCastException
-
存在条件,继承关系,方法需要重写,父类指向子类
(static方法不能重写,属于类,不属于实例,final 常量,private私有)
子类转化为父类,可能会丢失一些方法
多态存在的条件
-
有继承关系
-
子类重写父类方法
-
父类指向子类的对象
多态是方法的多态,属性没有多态
instanceof(类型转换)引用类型
判断两个类之间是否有父子关系
static关键字
package day9; public class Student extends Person { { System.out.println("匿名代码块"); } static{ System.out.println("静态代码块"); } public Student() { System.out.println("构造方法"); } public static void main(String[] args) { Student student = new Student(); //先运行静态代码区,再运行匿名代码区,最后运行构造方法 System.out.println("===================="); Student student1 = new Student(); //静态代码块只执行一次 } }
抽象类和接口
abstract修饰类变成抽象类
package day9; //接口有多继承,类没有多继承 public abstract class Name { //约束,有人来实现 //抽象方法,只有方法名,没有方法体 public abstract void doSomeThing(); //1.不能new抽象类,只能通过子类来实现:约束! //2.抽象类中可以写普通方法 //3.抽象方法必须在抽象类中 //抽象的抽象:约束 public static void main(String[] args) { } }
接口
-
普通类:只有具体的实现
-
抽象类:具体实现和规范(抽象方法)都有
-
接口:只有规范,自己无法写方法,专业的规范!约束和实现分离:面向接口编程
接口就是规范,定义的是一组规则,只需要遵守
作用:
-
约束
-
定义一些方法,让不同的人实现
-
public abstract方法
-
public static final属性
-
接口不能被实例化,接口中没有构造方法
-
implements可以实现多个接口,实现多继承
package day9; //interface 接口 //类 可以实现接口中 implements 接口 //实现了接口的类,就需要重写接口中的所有方法 //类可以实现多个接口,实现多继承 public interface Characterize { //接口中的所有定义其实都是抽象的public //接口中定义常量 //属性 public static final int AGE=99;//属性默认为public static final //方法 public abstract void run();//方法默认为public abstract int go(); void date(); int age = 0; }
内部类及OOP实战
一个java文件只能有一个public class,可以有多个class
package day9; public class InnerClass { //内部类 private int id; public void out() { System.out.println("这是外部类的方法"); } public class Inner { public void in() { System.out.println("这是内部类的方法"); } //获得外部类的私有属性 public void getId(){ System.out.println(id); } } //局部内部类 public void method(){ class under{ private int age; public void eat(){ System.out.println("吧唧吧唧"); } } } }
异常
-
检查性异常
-
运行时异常
-
错误
异常处理机制
-
抛出异常
-
捕获异常
异常处理的五个关键字
-
try
-
catch
-
finally
package day9; public class Demo { public static void main(String[] args) { int a=1; int b=0; try {//监控区域 System.out.println(a/b); }catch (ArithmeticException e){//遇到异常就执行catch System.out.println("程序出现异常,b不能为0"); }finally {//处理善后工作 System.out.println("finally"); } } }
try,catch一定要,finally可以不要(例如IO流的关闭工作)
捕获多个异常:从小到大捕获
-
throw
-
throws
package day9; public class demo02 { public static void main(String[] args) { try { new demo02().test(1,0); } catch (ArithmeticException e) { e.printStackTrace(); } System.out.println("++++++++"); } //假设这个方法处理不了这个异常,方法上抛出 public void test(int a,int b) throws ArithmeticException{ if (b==0){ throw new ArithmeticException();//主动抛出异常 } System.out.println(a/b); } }
自定义异常
-
创建自定义异常类
-
在方法中通过throw关键字来抛出异常对象
-
如果在当前抛出异常的方法中处理异常,可以使用try-catch语句来捕获异常并处理;否则在方法声明处用throws关键字来指明抛出给方法调用者的异常,继续进行下一步操作
-
在出现异常方法的调用者中捕获并处理异常
自定义异常总结
-
处理运行时异常是,采用逻辑去合理规避同时辅助try-catch处理
-
在多重catch块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常
-
对于不确定的代码,可以加上try-catch,处理潜在的异常
-
尽量去处理异常,切忌只是简单地调用printStackTrace()去打印输出
-
具体如何处理异常,要根据不同的业务需求和异常类型去决定
-
尽量添加finally语句块去释放占用的资源