1、封装
字面意思,把东西装起来:隐藏、保护、提供方便使用的方式(例如快递打包、水管)。在这里指,将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问,把尽可能多的东西藏起来,对外提供便捷的接口。
用private关键字将属性隐藏,提供公共的访问接口getter/setter,如果有所限制,在setter中进行设置。
好处:让编程变得简单,找对象、调方法就行。
1.1 private关键字
private关键字,对属性进行私有化,被private修饰的成员只能在本类中访问。
访问修饰符:访问权限控制
◉ public:公共的,整个工程都可以访问
◌ protected:受保护的(包级私有+子类),除了本包之外,继承该类的所有子类也可以访问
◌ 默认的(无关键字):包级私有,本类所在的包内所有的文件都可以访问
◉ private:私有的,本类内部才能访问
修饰符 \ 作用域 | 同一个类中 | 同一个包中 | 子类中 | 任何地方 |
---|---|---|---|---|
private | 可以 | 不可以 | 不可以 | 不可以 |
默认修饰符 | 可以 | 可以 | 不可以 | 不可以 |
protected | 可以 | 可以 | 可以 | 不可以 |
public | 可以 | 可以 | 可以 | 可以 |
被private修饰的成员,用之前我们调用成员变量方式会报错
//定义一个学生类
public class Student{
//private修饰的变量
private String name;
private int age;
private String gender;
}
==================================
//测试类
public class Test{
public static void main(String[] args){
Student s=new Student();
s.name="张三";//报错
}
}
所以我们在使用private私有化后,要提供公共的访问接口:getter/setter。
1.2 getter/setter访问接口
getter和setter分别对应属性的出口和入口:
setter方法:给成员变量赋值
getter方法:对外提供成员变量的值
如果有特殊的条件限制,只能在setter中对赋值进行设定
getter是为了获取属性值,所以必然有return语句
//定义一个学生类
public class Student {
//private修饰的变量
private String name;
private int age;
private String gender;
//权限修饰符用public 表示是公共的,在所有的地方都能调用这个方法
//setter方法:接收数据,给成员变量赋值,有参,无返回值
public void setName(String name) {//给name赋值
this.name = name;
}
//getter方法:对外提供,无参,有返回值
public String getName() {//对外提供name属性
return name;
}
//对年龄有限制,在setter方法中进行条件判断
public void setAge(int a) {
if(a>=18 && a<=22){
age = a;
}else{
System.out.println("年龄超出范围");
}
public int getAge() {
return age;
}
public void setGender(String gender) {
//当成员变量名和形参参名一样时,用this指向成员变量
//成员变量成员方法都需要用对象名调用,这里的this就代替了对象名
this.gender = gender;
}
public String getGender() {
return gender;
}
}
==================================
//测试类
public class Test {
public static void main(String[] args){
Student s1=new Student();
s1.setName("张三");
s1.setAge(16);
System.out.println(s1.getName()+"的年龄是"+s1.getAge());
Student s2=new Student();
s2.setName("李四");
s2.setAge(20);
System.out.println(s2.getName()+"的年龄是"+s2.getAge());
}
}
输出结果:
年龄超出范围
张三的年龄是0
李四的年龄是20
由于张三的年龄超出年龄范围,系统取默认值为0.
getter和setter方法快速自动生成的 快捷键
Alt+insert
如果有有参构造,有参构造中的赋值也应该调用setter,以便调用setter的限制
1.3 包
包,作为Java源代码的第一条语句,用package声明包,以分号结尾。
包名由小写字母组成,不能以圆点开头或结尾
package声明第一行(忽略注释)
其次是import
然后是
不要在src下直接写类,否则的话在别的包内是找不到这个类的
2、继承
2.1 extends关键字
子类共同的属性和方法,抽象出父类,子类用extends关键字基础父类的可见成员,java是单根继承,提高代码重用性,子类和父类满足is-a的关系
A extends B代表:A类继承了B类的成员属性和成员方法(可见的)。
在继承过程中,会默认创建父类对象,子类对象继承该父类对象的全部成员 ,实现代码重用。
java中只允许单根继承,一个类只能继承一个直接父类。(要想继承别的就定义一个“爷爷”类)
Object类 是 所有类的父类。
2.2 继承与构造方法
1)当父类不存在无参构造时,子类会编译报错,因此父类必须有无参构造
2)创建子类对象时,会先执行父类无参构造,再执行子类无参构造
public class Pet {//把Penguin和Dog公共的部分抽离出来做父类
private String name;
private int health;
private int love;
public Pet(String name, int health, int love) {
this.name = name;
this.health = health;
this.love = love;
}
public Pet() {
System.out.println("父类无参");
}
}
==========================================================
public class Cat extends Pet{
public Cat(){
System.out.println("子类无参");
}
==========================================================
public class TestPet {
public static void main(String[] args) {
Cat c=new Cat();
}
}
运行结果:
父类无参
子类无参
如果是创建有参对象 ,会先执行父类无参构造,再执行子类有参构造
public class Pet {//把Penguin和Dog公共的部分抽离出来做父类
private String name;
private int health;
private int love;
public Pet(String name, int health, int love) {
this.name = name;
this.health = health;
this.love = love;
}
public Pet() {
System.out.println("父类无参");
}
}
==========================================================
public class Cat extends Pet{
public Cat(){
System.out.println("子类无参");
}
public Cat(int test){
System.out.println("子类有参");
}
==========================================================
public class TestPet {
public static void main(String[] args) {
Cat c=new Cat();
}
}
运行结果:
父类无参
子类有参
如果在子类构造方法中用super(...)来指定父类有参,则不再调用父类无参
public class Pet {//把Penguin和Dog公共的部分抽离出来做父类
private String name;
private int health;
private int love;
public Pet(String name, int health, int love) {
System.out.println("父类有参");
this.name = name;
this.health = health;
this.love = love;
}
public Pet() {
System.out.println("父类无参");
}
}
==========================================================
public class Cat extends Pet{
public Cat(){
System.out.println("子类无参");
}
public Cat(int test){
super("aaa",1,1);
System.out.println("子类有参");
}
==========================================================
public class TestPet {
public static void main(String[] args) {
Cat c=new Cat();
}
}
按住Ctrl鼠标悬浮在super关键字上方,可以看见super关键字 指向父类的 有参构造
运行结果:
父类有参
子类有参
2.3 Object类
Object类 是 所有类的父类。
2.4 子类继承父类的...
非私有 | 私有private | |
构造方法 | 不能继承 | 不能继承 |
成员变量 | 能继承 | 能继承,但不能直接使用 |
成员方法 | 能继承 | 不能继承 |
- 继承public和protected修饰的属性和方法,不管子类和父类是否在同一个包里
- 继承默认权限修饰符修饰的属性和方法,但子类和父类必须在同一个包里
子类与父类要符合 is-a 关系的设计
is-a,顾名思义,是一个,代表继承关系。
如果A is-a B,那么B就是A的父类。
3、多态
同类型的对象,表现的不同形态。即 同一个引用类型,使用不同的实例对象而产生不同的操作结果,一个类型的方法在其子类中有多种不同的表现形式
父类的方法被多个子类重写的前提下,父类作为形参,子类对象作为实参在方法中调用了父类的被重写方法,会自动调用传入实参的重写后的子类方法
多态的前提:
- 有继承/实现关系
- 有父类引用指向子类对象
- 有方法的重写
实现步骤:
1、父子继承关系,且多个子类重写了父类的某一个方法2、父类的类型作为方法的形参类型,用形参调用父类的被重写的方法
3、在实际调用时,以子类对象作为传入的实参能根据传入的子类类型,自动调用该类中重写后的方法
好处:可扩展性强,维护性高,代码量较少,提高了重用性。但耦合性高。