JAVA面向对象二 三大特征
面向对象的特征是封装,继承和多态。这也是面向对象的重点和难点。在了解三大特征前,我们先了解下JavaBean。
JavaBean
JavaBean 泛指一些列的模板类,是一系列的统称
模板类|javabean|实体类|pojo…
属性私有化,公共的访问方式
私有的内容->配合公共访问方式一起使用
private 私有的 ,权限修饰符
被private修饰的成员只能在当前类中使用
公共访问方式
设置器 setter
访问器 getter
设置器和访问器其实就是公共的成员方法
Package和import
Package
包:和我们平时用的文件夹一样。管理众多的java资源;提供多重命名空间。
我们平时用idea时,写代码的首行都是会自动生成一个包的。
定义规范:全部小写,每个层级之间用 . 分隔;一般都是公司域名倒着写.功能名|模块名
import
之前想我们用的Scanner (键盘录入),这都是需要导包的,因此import就是导包的关键字。当我们想要在A类中使用B类,就哟啊使用import。(创建B类的对象,调用B类的静态内容)
注意的是 同包下的类 和 java.lang 下的内容是不需要导包的。
语法: import 包名.类名;
当一个包下需要多个类时,可以用 *****模糊匹配。import java.util.*;
静态导入 用 import static 只导入一个类中的某个静态的内容。
JavaBean开发规范
alt+insert->generate
1.类是公共的
2.至少提供一个空构造,可选择的提供带参构造
3.属性私有化
4.提供公共的访问方式 setter getter
5.至少提供一个空构造器
5.重写toString
6.重写equals
arl+insert 可以自动生成 构造器,setter and getter ,toString,equals
封装
封装是隐藏内部的实现细节,对外提供公共的访问方式。
方法 和(属性私有化,公共的访问方式) 都是封装的体现。
好处:可以提高代码的复用性,提高程序的安全性
因此我们自定义模板类,属性都应该私有化,并提供公共的访问方式。
属性私有化:用private(私有的) 修饰属性
公共的访问方式:使用设置器setter 和 访问器getter
public class Person {
private String name;//私有成员属性
public Person(){} //空构造器
public Person(String name){ //带参构造器
this.name = name;
}
//设置器: 为了私有的属性name赋值
public void setName(String name){
this.name = name;
}
//访问器: 为了获取私有属性name的值
public String getName(){
return name;
}
继承
继承可以提高代码的复用性,子类一旦继承父类就有权使用父类中的内容,并且子类还可以扩展,即拥有自己独有的内容。
java中的继承是单继承机制,即一个子类只能继承一个父类,但可以多实现(在接口中讲)。
单继承更加简单,但是不便于后期的维护,因此有了多实现来弥补其缺点,多实现会在之后的接口部分重点讲下。
//父类
class Person{
public String name;
public int age;
public void sleep(){
System.out.println("休息...");
}
}
//子类
//学生类
class Student extends Person{
public int id; //学生编号
//学习
public void study(){
System.out.println("正在学习...");
}
}
重写
方法的重写是方法体的重新实现。我们在继承父类的方法的时候,有些方法是不适用于子类的,因此子类可以对方法进行重写。
要求:是不同的类;有继承或者实现的关系;方法签名相同(方法名+参数列表)
注意与重载的异同:它们都是方法的特性
重载:同一个类的多个方法;方法名相同;参数列表不同(方法签名不同)
注意:
子类对象调用成员的时候,如果子类中有,就就近原则找子类的,子类没有找父类的
当子类中存在方法的重写,子类对象会调用子类中重写的方法,子类没有找父类
不能重写的方法:
1.被private修饰的方法 不能被重写
2.被 final 修饰的方法不能被重写
3.被 static 修饰的方法 不能被重写
并且如果子类中出现于父类静态方法同名的方法,要求也是静态的
检查重写的方式:
1.在行号的位置显示o箭头指向被重写的方法
2.在重写方法的上面添加一个@Override 强制检查此方法是否为一个重写方法,不是报错
重写的三个条件: 一般都是用相等的
1.== 子类重写方法与父类中的被重写方法 方法签名要求完全相等
2.<= 如果子类重写方法与父类中的被重写方法 返回值类型是基本数据类型,要求完全相等;引用数据类型,子类<=父类。 子类的方法是重写父类的方法,当时引用数据类型的时候,如果返回值都比父类的大,就相当于父类有个鸡蛋,然后你继承了一个金蛋,根本就继承不到。
,
3.>= 子类重写方法的权限修饰符>=父类中被重写方法的权限修饰符
就像是下面说到的多态,如果子类的权限都比父类小,在多态中父类都没有权限调用子类的重写方法,这显然是不行的。
//父类的方法
class Person{
public void sleep(){
System.out.println("人正在休息...");
}
}
//子类方法的重写
class Student extends Person{
@Override
public void sleep(){
System.out.println("学生正在休息...");
}
}
注意:@Override 放到重写的方法上面可以检查该方法是不是重写,如果不是就会报错。
访问权限修饰符
访问权限修饰符 : 修饰成员被访问的权限,不能修饰局部–>成员修饰符
修饰符 | 本类中 | 同包的类中 | 不同包下的子类 | 不同包的其他类 |
---|---|---|---|---|
private私有的 | √ | |||
default 默认的 | √ | √ | ||
protected 受保护的 | √ | √ | √ | |
public 公共的 | √ | √ | √ | √ |
default 修饰符在用的时候是省略不写的。一般的 class A 就是省略了default
super
super和this 比较像,因此要了解它们的区别
this关键字
1>用来指代当前对象(new)
构造器首行调用奔雷中的其他构造器 this(参数)
2> 区分同名变量问题 局部与成员
super
1> 指代父类对象
在子类构造器的首行通过super(参数)调用父类的构造器
2> 区分同名问题
如果子类与父类存在同名情况(成员),在子类中默认就近原则找子类的,如果想要找父类中的同名成员,使用super.调用
注意:如果子类中存在局部与成员同名情况,默认找局部,想要指代成员通过this.调用
如果没有同名问题,this.和super.都可以省略
如果子类构造器中没有显示调用父类的指定构造器,默认调用父类空构造super()
在一个构造器的首行,this()与super()不能同时存在
当存在子父类继承关系下,创建子类对象–>先父类后子类
this和super不能使用在static环境中
final
final是最终的意思,既可以修饰局部,也可以修饰成员。
1.被final修饰的变量为常量(标识符的规范)
2.被final修饰的方法不能被重写
3.被final修饰的类不能被继承
Object
我们可以形象的称为“老祖宗类”,它是所有类的父类,也就是说java中的所有类都会直接或间接的继承自Object,同样Object中定义的成员,只要子类有访问权限,都是可以使用的。
下面重点介绍object中的两个重点方法 equals 和 toString
equals
作用是比较两个对象是否相等,但是程序默认比较的是对象的地址,而我们在运用的时候是比较对象的内容,而非地址,因此我们需要对其进行重写。
object中的代码:
public boolean equals(Object obj) {
return (this == obj);
}
重写后的:
@Override
public boolean equals(Object obj) {
//增强程序健壮性 先过滤一下如果地址相等,就是一个对象,不需要比较内容
if(this==obj){
return true;
}
//判断参数是否为null,预防空指针异常
if(obj!=null){
//先把obj从Object类型强转为User类型,因为想要调用 User的成员变量name
User other = (User)obj; //other就是参数对象 强转
//如果用户名相等返回true,如果用户名不相等,直接返回false
if(this.name.equals(other.name)){
return true;
}
}
return false;
}
//使用
public static void main(String[] args) {
User u = new User("zhangsan"); //创建User对象,并调用带参构造器为对象初始化信息
User u1 = new User("lisi");
System.out.println(u.equals(u1));//比较内容
System.out.println(u==u1);//比较地址
}
因此我们在javabean中,如果需要也是要重写equals方法的。我们也可以用alt+insert 快捷键自动生成equals重写方法。
toString
可以将对象以字符串的形式返回,同样返回的也是打印对象的地址,因此也需要我们进行重写,才能返回对象的基本信息。
@Override
public String toString() {
return "姓名-->"+name;
}
return后面想返回什么内容就可以写什么内容,返回的是String 类型的。和equals一样,在javabean中,如果用到也是需要重写方法的,也可以用alt+insert自动重写方法。
多态
定义
多态是一种事物的多种形态|表现形式。是在继承和实现的前提下的。
语法 : 父类 引用 = 子类的对象 (父类的引用指向子类的对象)
Parent p = new Child();
多态的调用:如果是成员方法,多态会调用子类重写方法,但子类的新增方法不可见。
如果是成员变量,编译和运行都是看父类的
类型转换
在多态的前提下,如果我们想要调用子类的新增内容呢,这就需要用到转型。多态其实也就是自动向上转型。而向下转型和我们之前学到的基本数据类型的转换时一样的,可以叫做强转。
上面定义的p是Parent(父类)的,因此我们强转下。Child c = (Child) p;
但是这样写又会遇到一个问题,当Parent 有一个Kid的子类,因为之前多态是指向的Child类的对象,这时我们如果 Kid k = (Kid) p;这样强转,就会遇到类型转换异常。
为了解决类型转换异常,我们可以用 一个运算符 instanceof
引用 instanceof 类型: 判断前面的引用指向的对象是否为后面类型的对象,或者前面的引用是否指向后面类型子类的对象,如果是返回true,不是返回false
编译:只检查前面的引用与后面的类型是否在一条继承体系上,如果在编译就不报错,不在编译就报错
System.out.println(p instanceof Child);//true
System.out.println(p instanceof Kid);//false
System.out.println(p instanceof Object);//true
System.out.println(p instanceof Son);//Child 的子类 false
instence是实例的意思, p instenceof Child 可以理解为p是Child的实例吗?因为本身是指向Child类的,所以是Child的实例。同样也是Child父类的实例。但对于Child是兄弟的Kid以及其儿子Son,p并不是他们的实例。
面向对象是有些抽象的,我们只有多接触才会有更进一步的了解,坚持学习下去,一定会有更多的见解的。