8.1 封装
将一系列零碎的代码用方法的形式把它组装在一起形成一个完整的功能就是封装(这是广义的封装)。狭义的封装,就是将以前对类的成员变量的赋值取值操作把它们放到方法中去,用方法的方式来实现赋值和取值。
代码语言:javascript复制People zhangpeng = new People();
zhangpeng.name="张鹏";
zhangpeng.age=25;
zhangpeng.gender='男';
zhangpeng.height=179;
System.out.println(zhangpeng.name);
意思就是把这些赋值取值的操作不要直接暴露在外面,用方法的形式来操作
- 良好的封装能够减少耦合。
- 类内部的结构可以自由修改。
- 可以对成员变量进行更精确的控制。
- 隐藏信息,实现细节。
面向对象的六大原则
1、单一职责
低耦合(两段代码之间的关联性不要太强) , 高内聚(每一个方法只完全一个功能,单一职责)
狭义上的封装是针对对成员变量,一个封装有两个方法,一个负责赋值(set),一个负责取值(get),封装方法的命名方式set属性名 get属性名,这是一种约定,不可随意改变,后面学习框架的时候都必须要遵循这种约定。
语法:
赋值的方法
public void set属性名(数据类型 变量名){
this.属性名=变量名
}
注意: 1、set属性名 第一个字符要大写 2、set属性名(数据类型 变量名) 数据类型与要赋值的属性类型一致,变量名与属性同名
取值的方法
public 数据类型 get属性名(){
return this.属性名;
}
代码语言:javascript复制//成员变量从规范上来讲不应该这样定义
//定变量
String color;
String breed;
String name;
int age;
String greder;
/*
狭义上的封装
*/
//赋值的封装
public void setColor(String color){
this.color=color;
}
//取值的封装
public String getColor(){
return this.color;
}
public void setBreed(String breed){this.breed=breed;}
public String getBreed(){return this.breed;}
public void setAge(int age){
if(age>=0&&age<=120){
this.age=age;
}else{
this.age=18;
}
}
public int getAge(){
return this.age;
}
public void setGreder(String greder){
if("公".equals(greder)||"母".equals(greder)){
this.greder=greder;
}else {
this.greder="公";
}
}
public String getGreder(){
return this.greder;
}
public void setName(String name){this.name=name;}
public String getName(){return name;}
8.2 包
包就是文件夹,用于对Java文件进行归类管理,包的创建com.qf.entitys entity代表的是实体的意思
创建包的步骤
1、第一种 对java文件夹右击-->New--> package建包
每层类名之间用.分隔,每层名字就是一个文件夹
第二种,创建类的同时创建包
用包对java类文件进行集中管理以后,类会在第一行代码描述出该类所在包的位置
package com.qf.entitys; 必须放在第一行。
在其他包中或项目中使用这个类的时候,必须进行导包操作
import com.qf.entitys.Dog
8.3 访问修饰符
访问修饰符 | 说明 |
---|---|
private | 私有的, 只能在本类进行调用 |
public | 公共的, 在任何类中都可调用 |
protected | 受保护的, 在子类中可以调用父类的方法属性 |
default | 默认的, 在同一个包下可以进行调用 |
8.3.1 default
成员变量和成员方法访问修饰符的位置什么都不写,该变量和方法的访问级别就是同一包
从上面的图片可以看出之前可以直接使用对象名.属性名赋值的方式现在报错了,那就是因为使用的默认访问级别且Main类和People类不在同一包中
- 8.3.2 public public公共的,所有地方都能访问。
成员变量如果不进行继承的时候就用private进行修饰,如果外部要对成员变量赋值和取值时,需要提供封装方法。
8.4 继承
8.4.1 继承就是上一辈留给下一辈的一些东西。
下面层级的分类比上面层级分类的内容会更细腻。
学生类
属性: 姓名,性别,年龄,班级, 学号
老师类
属性: 姓名,性别,年龄,班级,工号 , 课程
父类,子类
从多个类中找出相同的属性和方法放在父类中,父类用于描述多个不同类的相同的内容,子类只需要描述出不同的内容,相同的内容从父类中进行继承,而从减少代码的冗余。is-a关系,老虎是动物,兔子是动物,学生是人,老师是人
继承的语法:
public class 子类名 extends 父类名{
}
父类 :A 子类 B
public class B extends A{
}
代码语言:javascript复制父类
package com.qf.oop;
public class QianFeng {
//相同的属性
private String name;
private int age;
private String gender;
private int id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
//相同的行为
public void show(){
System.out.println("People{"
"name='" name '''
", age=" age
", gender='" gender '''
", id=" id
'}');
}
}
代码语言:javascript复制学生类
package com.qf.oop;
public class Student extends QianFeng { //extends QianFeng继承 QianFeng
//学生特有的属性
private String clazz; //班级
public String getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
}
代码语言:javascript复制老师类
package com.qf.oop;
public class Teacher extends QianFeng {
//老师特有的属性
private String subject;
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
}
代码语言:javascript复制调用类
package com.qf.start;
import com.qf.oop.Student;
import com.qf.oop.Teacher;
public class Main3 {
public static void main(String[] args) {
Student student=new Student();
student.setId(1);
student.setName("张鹏");
student.setGender("男");
student.setClazz("java2202");
student.setAge(25);
student.show();
Teacher teacher=new Teacher();
teacher.setId(1);
teacher.setName("李东升");
teacher.setAge(32);
teacher.setGender("男");
teacher.setSubject("java");
teacher.show();
}
}
从运行结果无法区别谁是老师谁是学生,因为show方法是来自于父类,这里的调用也是调用的父类的方法。还有一点,子类可继承父类中除了private修饰的所有内容
思考:学生类中有班级,老师类中有课程,如果我想区分开来进行显示怎么办。
8.4.2 父类方法中的重写
代码语言:javascript复制学生类
public class Student extends QianFeng {
private String clazz; //班级
public String getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
public void Desc(){
System.out.println("学生说:n姓名:" this.getName() "t年龄:" this.getAge() "t性别:" this.getGender() "t工号:" this.getId() "t所在班级:" this.clazz);
}
}
代码语言:javascript复制老师类
public class Teacher extends QianFeng {
private String subject;
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public void Desc(){
System.out.println("老师说:n姓名:" this.getName() "t年龄:" this.getAge() "t性别:" this.getGender() "t工号:" this.getId() "t所教课程:" this.subject);
}
}
因为父类中的show方法无法满足现在子类的需要,现在这两个子类,自己写了个Desc的方法来做自我介绍。语法,逻辑上都可以实现,但是违反了oop原则,自我介绍属于相同功能, 而不是特有功能,这种做会将后面的一个知识多态实现不了,既然是父类中的show方法无法满足子类中的需要时,这时正确的做为是重写父类中的show方法
方法重写: 发生在继承中,子类重写父类中的方法,方法的返回值 方法名,方法的参数要一模一样,实现代码不同,叫方法的重写。只要子类中重写了父类的方法,再调用的时候就不会再去调用父类中的方法而是调用子类中的方法
代码语言:javascript复制学生类
public class Student extends QianFeng {
private String clazz; //班级
public String getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
public void show(){
System.out.println("学生说:n姓名:" this.getName() "t年龄:" this.getAge() "t性别:" this.getGender() "t工号:" this.getId() "t所在班级:" this.clazz);
}
}
代码语言:javascript复制public class Teacher extends QianFeng {
private String subject;
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public void show(){
System.out.println("老师说:n姓名:" this.getName() "t年龄:" this.getAge() "t性别:" this.getGender() "t工号:" this.getId() "t所教课程:" this.subject);
}
}
代码语言:javascript复制@Override //用于说明当前的方法是来自于父类中(重写父类中的方法)
public void show(){
System.out.println("老师说:n姓名:" this.getName() "t年龄:" this.getAge() "t性别:" this.getGender() "t工号:" this.getId() "t所教课程:" this.subject);
}
@Override(文档类注解) 只是说明一下这个方法重写父类中的方法,重写父类中的方法你加不加这个 @Override 都没关系,只要你的格式正确就能形成重写,最好在重写的方法加上这个@Override。
@Override 注解--> Java中有很多的注解
注解 :
1、运行时起作用
2、写入到class文件中
3、文档类注解
运行时注释:
@SpringBootApplication
@Resource
@Service
@Controller..... 运行时
Lombok 写入到class文件中
@Data
- 8.4.3 super
super可以去调用父类中的private之外属性,方法,以及构造。super的使用形式和this一样,只不过super调用的是父类中的内容。
现在在创建一个对象时,进入到子类的构造方法以后会先去调用父类的构造方法,如果父类的默认构造被覆盖,子类将会报错,这时在子类的构造方法中需要使用super()去显示的调用一下父类中的构造才行。
代码语言:javascript复制public class QianFeng {
public QianFeng(String name, int age, String gender, int id) {
this.name = name;
this.age = age;
this.gender = gender;
this.id = id;
}
}
代码语言:javascript复制public class Student extends QianFeng {
public Student(){
super(null,0,null,0);
}
}
这样只能保证不报错,但是呢,没有意义,人家在这样设计,肯定代表着有可能在创建对象的时候就需要把所有的属性都赋值,所以子类正确的写法
代码语言:javascript复制public class Student extends QianFeng {
public Student(String name, int age, String gender, int id,String clazz) {
super(name,age,gender,id); //将相关父类的值,直接调用父类对应构造方法进行赋值操作
this.clazz=clazz; //子类特有的属性单独的赋值
}
}
如果即想保留默认构造,也想拥有全参构造怎么办
现在单独的写出子类的默认构造依然报错,原因是因为子类的默认构造会自动的去调用父类的默认构造,但是父类的默认构造已经被覆盖,所以这里报错
使用super调用父类中的方法时
父类中的方法被子类继承以后,在子类可以通过this访问也可以通过super访问,在可读性上this表示本身当前的对象,super表示的父类,用super调用一眼就能知道这个方法或属性来自于父类中。
继承中的protected访问修饰符,受保护的。你类用protected修饰的方法或属性在子类中可以直接访问,在其他地方不能访问。
在main方法中时
在main方法中还是只能通过封装方法来进行操作属性