封装
1.封装
1.概念:
将类中的属性隐藏在类的内部,使用private修饰,不让外部类直接访问,提供一对公开的getter、setter方法,getter方法用于获取属性值(读取),setter方法用于设置属性值(写入)
2.封装的步骤:
(1)属性私有
(2)方法公开
3.封装的好处:
(1)便于使用者正确使用系统,防止错误修改属性
(2)降低了构建大型系统的风险
(3)提高程序的可重用性
(4)降低程序之间的耦合度
package com.qfedu.test1;
public class Student {
private String name;
private int age;
private double score;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
if(age > 0 && age <= 140) {
this.age = age;
}else {
System.out.println("年龄不合适,使用默认年龄");
this.age = 18;
}
}
public int getAge() {
return age;
}
public void setScore(double score) {
if(score >= 0 && score <= 100 ) {
this.score = score;
}else {
System.out.println("分数不合适,使用默认分数");
this.score = 60;
}
}
public double getScore() {
return score;
}
public void printStu() {
System.out.println("学生名字是" + name);
System.out.println("学生分数是" + this.getScore());
System.out.println("学生的年龄是" + getAge());
}
public static void main(String[] args) {
Student stu1 = new Student();
stu1.name = "赵四";
stu1.age = -20;
stu1.score = -50;
// 以上代码 在实际开发中不会将测试类和实体类写在一起
}
}
2.访问权限
1.类的访问权限:
public:本项目中都可以访问
默认不写:只在同一个包中可以访问
2.类成员的访问权限(包括属性、方法):
private:本类中可以访问
默认不写:本类、同一个包中可以访问
protected:本类、同一包中、不同包的子类中可以访问
public:本类、同一包中、不同包的子类中、任何地方
如果在同一个类中需要访问两个同名但是不同包的类,那么可以使用全限定名(包名+类名)来访问。
3.通过eclipse编辑器观察:
(1)红色的方框表示私有private修饰的
(2)蓝色的三角表示默认修饰的
(3)黄色的圆角的方框是protected
(4)绿色的圆点表示public修饰的
作用域 修饰符 | 同一个类中 | 同一个包中 | 子类中 | 任何地方 |
---|---|---|---|---|
private | 可以 | 不可以 | 不可以 | 不可以 |
默认修饰符 | 可以 | 可以 | 不可以 | 不可以 |
protected | 可以 | 可以 | 可以 | 不可以 |
public | 可以 | 可以 | 可以 | 可以 |
3.static关键字
3.1static修饰属性
1.适用场景:
修饰属性:表示此属性属于类级别的,不依托于对象而存在,将被所有的对象共享,在内存中只有一份拷贝。
2.类加载的过程:
(1)当我们第一次访问一个类时,JVM将在方法区加载此类的class文件,并且只加载一次。(多次创建对象也是加载一次,可以简单理解为,完整运行一次,即是加载一个类一次)
(2)在堆中开辟一块空间,并且所有的实例变量将有默认值
(3)将堆中的地址赋值给栈中的引用
3.方法区:系统分配的一个内在逻辑区域,只是逻辑的概念
方法区是JVM提供的一个规范,javaJVM的名字hotspot
JDK8之前java中的方法区叫作永久代(JVM中具体的实现)
JDK8之后改名为元数据(JVM中具体的实现)
4.方法区和堆:
方法区和堆共享内存空间,但是方法区是静态分配内存的,我们所使用的static修饰的属性、方法,代码块都是只要类被加载,就存在的(因为不能动态回收垃圾,所以不能滥用static)。堆是随着程序的执行动态分配内存的
举例:我们的姓氏是出生就存在的,相当于静态的,我们的性格是随着成长生成的,相当于动态的。
栈:先进后出
堆:先进先出
3.2static修饰方法
static修饰的方法称之为静态方法,可以通过类名访问,不需要创建对象
1.静态方法、代码块中能不能直接访问非静态的属性和方法?
不能,必须要先创建对象(有静态的,不一定有对象,而非静态是随着对象而生)
2.静态方法、代码块中能不能直接访问静态的属性和方法?
可以,静态与静态之间互相可以直接访问。
3.非静态的属性和方法能不能访问静态的属性和方法?
当然可以(有非静态的属性和方法当然有对象了)
package com.qfedu.test5;
public class TestStaticMethod {
public static void m1() {
System.out.println("静态方法1");
}
public static void m2() {
System.out.println("静态方法2");
}
public void m3() {
System.out.println("普通方法3");
}
public static void main(String[] args) {
m1();
TestStaticMethod tsm = new TestStaticMethod();
tsm.m3();
}
}
3.3static修饰代码块
被static修饰的代码块,称之为静态代码块,当JVM加载类的时候,就执行,多个静态代码块按照顺序执行,并且只执行一次,因为类只加载一次
适用场景:当我们需要做一些前置的操作,比如连接数据库,或者初始化数据。
普通代码块:直接一对大括号,只要对象创建就会被执行。
注意: 类只被加载一次,哪怕是创建N个对象,也只执行一次静态代码块
package com.qfedu.test5;
public class TestStaticCode {
static int num = 20;
String name;
static {
System.out.println("静态代码块1");
}
static {
// System.out.println(name);
System.out.println(num);
System.out.println("静态代码块2");
}
public void m1(){
System.out.println(num);
}
{
System.out.println(num);
System.out.println("普通代码块1============");
}
{
System.out.println("普通代码块2=============");
}
public static void main(String[] args) {
// 静态代码块 当我们的类被加载 就会被执行 多个静态代码块按照顺序执行 并且只执行一次
// 用于一些前置的操作 或者 数据的初始化操作
// TestStaticCode tsc1 = new TestStaticCode();
//
// TestStaticCode tsc2 = new TestStaticCode();
//
// TestStaticCode tsc3 = new TestStaticCode();
System.out.println(TestStaticCode.num);
}
}
4.继承
4.1extends关键字
1.实现方式:使用extends关键字
2.继承优点:实现代码重用,统一、简化程序结构
3.继承:java是单根继承的,一个类只能有一个直接父类,可以有N个间接父类。(单继承,多实现)
4.可以继承哪些内容?
(1)public修饰的属性和方法
(2)protected修饰的属性和方法
a.protected修饰的方法在不同包子类的情况下,只能继承,不能直接访问
(3)默认修饰的属性和方法,要求父子类在同包。
5.不能继承哪些内容?
(1)private修饰的属性和方法
(2)构造方法
(3)默认修饰的属性和方法,但是父子类不在同包。
4.2super关键字
super关键字表示父类对象,可以访问:
1.父类的属性,直接super+.访问,访问规则结合访问修饰符权限
2.父类的方法,直接super+.访问,访问规则结合访问修饰符权限
3.父类的构造方法,super(形参列表)
a.子类默认访问父类的无参构造方法,除非子类显式调用父类的有参构造方法。(编译器会自动在第一行插入super())
b.使用this关键字访问本类中的其他构造方法,将直接默认调用父类的无参构造方法,此构造方法**
不能调用父类的有参
**(但是可以在被调用的其他本类构造方法中调用父类的构造函数,但这样用没意思啊。。。)。因为this和super在访问构造方法时,只能是用一个。都必须在构造方法的第一句。
执行顺序:
当进行无参构造时,先调用父类无参构造器,然后调用子类无参构造器;当进行含参构造时,先调用父类含参构造器,然后调用子类含参构造器
package com.qfedu.animal;
public class Pet {
protected String name;
protected int health;
protected int love;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
public int getLove() {
return love;
}
public void setLove(int love) {
this.love = love;
}
public Pet() {
System.out.println("父类无参构造方法");
}
public Pet(String name,int health , int love) {
this.name = name;
this.health = health;
this.love = love;
}
protected void print() {
System.out.println("宠物的名字是" + this.getName() + "宠物的健康值是" + this.getHealth() + "宠物的爱心值是" + this.getLove());
}
}
package com.qfedu.animal;
/**
* 子类访问父类的构造方法
* 子类默认调用父类的无参构造方法
* 除非子类显式的调用父类的有参构造方法
* 有参构造方法和无参构造方法只能调用一个
* 调用父类的构造方法 必须在子类构造方法的第一句
* @author WHD
*
*/
public class Dog extends Pet{
private String strain;
public String getStrain() {
return strain;
}
public void setStrain(String strain) {
this.strain = strain;
}
public Dog(String strain) {
this.strain = strain;
}
public Dog(String name,int health , int love ,String strain) {
// this(strain);
super(name, health, love);
System.out.println("使用父类的构造方法初始化子类对象");
}
public Dog() {
// super();
}
public Dog(int health,int love ,String name,String strain) {
System.out.println("使用父类的属性初始化子类对象,使用super关键字访问父类属性");
super.name = name;
super.love = love;
super.health = health;
this.strain = strain;
}
public void printDog() {
System.out.println("狗狗的品种是" + this.getStrain());
super.print();
}
}
每日问题
1.封装的作用,实现封装的步骤?
2.封装中get和set方法分别作用?
3.现有String name,int age手写实现封装
4.根据第三题提供的属性手写所有的构造方法
5.包的命名规范是什么?
6.如何在一个类中访问同名不同包的类
7.类的访问修饰符有哪些,分别代表什么意义?
8.类的成员访问修饰符有哪些,分别代表什么意义?
9.目前为止,我们学习过的内容你有哪些地方是不会的?
你认为这些知识点不会是因为什么?
10.static修饰的成员变量有什么特点,如何访问
static修饰的方法与普通方法有什么区别, /如何访问
static修饰的代码块
11.你觉得怎样预习一个新的知识点 ?
解答
1.封装的作用,实现封装的步骤?
更好的使用系统,防止错误的修改属性,降低构建大型系统的风险,降低程序的耦合
属性私有
方法公开
2.封装中get和set方法分别作用?
get获取信息
set设置值
3.现有String name,int age手写实现封装
private String name;
private int age;
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
4.根据第三题提供的属性手写所有的构造方法
public 类名(String name,int age){
this.name = name;
this.age = age;
}
public 类名(String name){
this.name = name;
}
public 类名(int age){
this.age = age;
}
5.包的命名规范是什么?
域名倒置,全部小写,不能以点开头或者结尾
6.如何在一个类中访问同名不同包的类
使用全部限定名,包名+类名
7.类的访问修饰符有哪些,分别代表什么意义?
public 表示在本项目中都可以访问
默认不写 同包中可以访问
8.类的成员访问修饰符有哪些,分别代表什么意义?
private 本类中
默认 同包中
protected 同包 + 不同包的子类
public 本项目中
9.目前为止,我们学习过的内容你有哪些地方是不会的?
你认为这些知识点不会是因为什么?
10.static修饰的成员变量有什么特点,如何访问
不依托于任何对象存在,在内存中只有一份拷贝,类名调用
static修饰的方法与普通方法有什么区别, /如何访问
静态方法,通过类名直接访问
static修饰的代码块
在加载类的时候执行,多个代码块按照顺序执行,并且只执行一次
11.你觉得怎样预习一个新的知识点 ?
这个知识点是什么?
如何实现?
为什么使用?
使用以后对比没有使用之前有什么好处?