12-OOP 面向对象编程[OOP特性、接口、内部类]
①.面向对象的三大特性
-封装
要求:“该露的露,该藏的藏”
程序要求“高内聚,低耦合”。
-高内聚就是类内部数据的操作细节自己完成,不允许外部干涉;
-低耦合就是仅暴露少量的方法供外部调用。
封装(数据的隐藏):通常,应该禁止直接访问对象中数据的实际表示,而应通过接口来访问,这称为信息的隐藏。
“属性私有,get / set”
public class Student {
//属性私有
private String name; //名字
private int id; //学号
private char sex; //性别
private int age; //年龄
//使用private关键字修饰后,这些属性就不能直接被外部调用了
//'name' has private access in 'com.oop.oppfeature.Student'
//如果需要修改这些属性,就需要提供一些方法
//需要设置一些public的get与set方法
//get获得这个数据
public String getName(){
return name;
}
//set设置这个数据
public void setName(String name){
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
if (sex == '男' || sex == '女'){
this.sex = sex;
}else{
System.out.println("非法输入!");
}
}
public static void main(String[] args) {
Student s1 =new Student();
s1.setSex('1'); //输出:非法输入!
}
}
- 封装的好处:
可以提高程序的安全性,保护数据
隐藏代码的实现细节
统一接口
增加系统的可维护行- 生成JavaBean快捷键
Alt + Shift + insert —> getter and setter
右键—>Generator —> getter and setter
-继承
本质:是对某一批类的抽象,从而实现对世界的更好的建模。
extends的意思是“扩展”,子类,是父类的扩展。
Java中只有单继承,没有多继承
继承是类与类的一种关系。除此之外,类和类之间还有依赖、组合、聚合等。
继承关系的两个类,一个为子类(派生类),一个为父类(基类),子类继承父类,使用extends关键字来声明
//人 是一个大的概念,也是对类的抽象
public class Person {
//public
//protected
//default
//private 属性修饰符优先级
//父类自己的属性应该私有,需要修改调用应该设置get set接口
private double money = 10000000;
//Ctrl + H 查看继承树
public void say(){
System.out.println("说了一句话");
}
public static void main(String[] args) {
Student student = new Student();
student.say(); //是Person类中的方法,子类继承父类的所有非私有方法
//在Java中所有的类都直接或间接继承Object类
Person person = new Person();
person.hashCode();
}
}
子类会继承父类的所有public方法
Java中所有的类都直接或者间接的继承Object类
·super详解
super的作用:可以调用父类中的非私有方法,可以调用父类的构造器。
super注意点:
- super()调用父类的构造方法,必须在子类构造方法的第一句
- super只能出现在子类的方法中,super()只能出现在子类的构造方法中
- super与this不能同时调用构造方法
super 与 this的区别
- 代表对象不同:
this:本来的调用者这个对象
super:代表父类的引用- 前提不同:
this:在非继承状态也能使用
super:只能在继承状态下使用- 构造方法不同:
this:调用本类构造
super:调用父类构造
·方法的重写
方法重写的规则:需要有继承关系,子类重写父类的方法
- 方法名必须相同
- 参数列表必须相同
- 修饰符范围可以扩大,但是不能缩小
public - protected - default - private- 抛出的异常:范围可以被缩小,但不能扩大:ClassNotFoundException - Exception(大)
子类的方法必须和父类一致,但是方法体不同!
为什么需要重写?
- 子类不一定需要,不一定满足于父类的功能
Alt + insert —> override
注意方法的重写和方法的重载的区别
方法重载的规则:
- 方法名称必须相同
- 形参列表必须不同(个数不同 / 类型不同 / 参数排列顺序不同等)
- 方法的返回值类型可以相同,也可以不相同。
- 仅仅返回值类型不同是不足以构成方法的重载的。
-多态
可以实现动态编译:提升类型的可扩展性
同一个方法可以根据发送对象的不同而采取多种不同的处理方式。
一个对象的实际类型是确定的,但可以指向的引用的类型有很多。
多态存在的条件:
- 有继承关系,父类子类之间有联系才能建立多态
否则会造成类型转换异常 ClassCastException!- 子类重写了父类的方法
- 父类的引用对象指向子类 Father f1 = new Son();
多态注意:
- 多态是针对方法来说的,属性没有多态
- 不能重写的方法
static 方法,从属于类不属于实例
final 常量
private 方法,私有方法
·instanceof 关键字与类型转换
instanceof 判断两个对象的从属关系
public static void main(String[] args) {
//Object --> Person --> Student
// --> Teacher
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 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("===================================");
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
//Inconvertible types;
//System.out.println(student instanceof Teacher); //编译报错! 同级比较
// System.out.println(person instanceof String); //编译报错! 同级比较
//System.out.println(X instanceof Y); //能不能编译通过主要看X指向的类型是否是Y的子类型
}
}
类型转换
把子类转化为父类,向上转型,不用强制转换 可能会丢失方法
把父类转化为子类,向下转型,需要强制转化 可能丢失精度
意义:不用new一个新的类,通过类型的转化就可以调用不同的类型的方法,提高代码利用率。
//Person为Student父类,go为Student中的方法
public static void main(String[] args) {
//类型之间的转化:基本类型转化 高>低 64 -> 16 -> 8 ...
// 父类 -> 子类
//高 低
Person p1 = new Student();
//将student对象转换为Student类型,就可以使用Student类型的方法了
Student stu = (Student) p1;
//可以使用student类型的方法了
stu.go();
//子类转换为父类有可能丢失自己本来的一些方法
Student student = new Student();
}
·static关键字
- 静态属性(变量),从属于类,public static int age;
可以直接被类所使用Student.age; 不用通过new对象就能访问- 静态代码块,从属于类,在类加载的时候就会被一起加载,并且只会加载一次。
- 静态的方法,和类一起加载的,不能被继承的。
- 静态的导入包 import static java.lang.Math.PI;
可直接在之后的语句中直接使用 double d2 = PI;
import static java.lang.Math.random;
//static:
public class Student {
private static int age; //静态变量 多线程
private double score = random(); //非静态变量
public void run(){}
public static void go(){
System.out.println("go to");
}
{
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.age);
// System.out.println(Student.score);
// 报错:Non-static field 'score' cannot be referenced from a static context
}
}
②.抽象类和接口
-抽象类
abstract修饰符可以用来修饰方法也可以用来修饰类
如果用来修饰方法,那这个方法就是抽象方法
如果用来修饰类,那么该类就是抽象类。
抽象类不能用new关键字来创建对象,它是用来让子类继承的。
抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的。
注意:子类如果继承抽象类,那么必须实现抽象类没有实现的抽象方法,否则该子类也需要声明为抽象类。
//abstract 抽象类
public abstract class Action {
//约束,要求别人帮我们实现
//abstract,抽象方法,只有方法的名字,没有方法的实现!
public abstract void doSomeThing();
//1.不能new这一个抽象类,只能靠子类去实现它:约束!
//2.抽象类当中也以写普通方法,但是抽象方法必须要在抽象类当中
//3.抽象类存在的意义:将多个类的共同特点抽象出来,再重新写某一个类的时候,提高现有代码的使用效率
}
//抽象类的所有方法,继承了它的子类,都必须要实现它的方法,除非该类也是抽象类
//extends 有局限性,Java只能单继承 但是接口解决了这个问题,接口可以多继承
public class AType extends Action{
@Override
public void doSomeThing() {
}
}
-接口
普通类:只有具体的实现
抽象类:具体实现和规范(抽象方法)都有
接口:只有规范!自己无法写方法,专业的约束!约束和实现分离:面向接口编程。
接口就是规范,定义的是一组具体的规则,体现了在现实中“如果你是…则必须能…”的思想
接口的本质就是契约,如同法律,一旦制定,那大家都必须要遵守。
面向对象-OO 的精髓,是对 对象 的抽象。
关键字:interface
注意:
- 接口中定义的方法都是抽象的默认为public abstract 抽象方法
- 接口中定义的所有量都是默认public static final 常量
//interface关键字可以定义接口,接口都需要相应的实现类
public interface UserService {
//接口中的所有定义的方法都是抽象的 默认 public abstract
public abstract void run(String a);
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
//接口当中定义的量都是常量
public static final int AGE = 99;
String NAME = "iFinder";
}
public interface TimeService {
void timer();
}
接口的实现
- 一个类可以通过implements实现接口
- 通过逗号分隔,可同时实现多个接口
- 实现了接口的类,必须重写接口的方法
public class UserServiceImpl implements UserService,TimeService{
@Override
public void run(String a) {
}
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void update(String name) {
}
@Override
public void query(String name) {
}
@Override
public void timer() {
}
}
③.内部类
-内部类
- 定义:内部类就是在一个类的内部再定义一个类。
比如,A类的内部定义一个B类,那么B类就是A类的一个内部类,A类就是B类的外部类。- 分类:
成员内部类
静态内部类
局部内部类
匿名内部类
成员内部类:
在类的内部定义,可以获得外部类的一些私有的属性。
通过外部类的实例变量来新建内部类对象。
public class Outer {
private int id = 144000;
public void out(){
System.out.println("这是外部类的方法");
}
public class Inner{
public void in(){
System.out.println("这是内部类");
}
//内部类可以获得外部类的私有属性
public void getId(){
System.out.println(id);
}
}
}
public static void main(String[] args) {
//new关键字,新建一个外部类
Outer outer = new Outer();
//通过外部类来实例化内部类
Outer.Inner inner = outer.new Inner();
inner.in(); //输出:这是内部类
inner.getId(); //输出:144000
}
匿名内部类:
没有名字的初始化类,不用保存到变量当中
public class NoName {
public static void main(String[] args) {
//匿名内部类,没有名字的初始化类,不用保存到变量中
new Apple().eat();
}
}
class Apple{
public void eat(){
System.out.println("1");
}
}