封装
- 面向对象三大特征:封装、继承、多态
- 面向对象四大特征:封装、继承、多态、抽象
- 为了防止随意给对象属性赋值可能存在的隐患,我们可以将属性进行封装,封装到类的内部,外部就无法直接访问属性,必须通过类提供的方法来访问。
- 封装的步骤:
- 修改属性的访问权限;
- 提供外部代码可以直接调用的方法完成赋值;
- 在setter方法中加入属性的逻辑控制,确保数值的正确性;
public class Student {
private int age;
private String name;
private char gender;
private String password;
public void setAge(int age){
if(age <= 0){
System.out.println("年龄不合法!已经赋予默认值 3");
this.age = 3;
}else{
this.age = age;
}
}
public void setName(String name) {
this.name = name;
}
public void setGender(char gender) {
this.gender = gender;
}
public void setPassword(String password) {
this.password = password;
}
public void show(){
System.out.println("用户信息如下");
System.out.println("年龄" + this.age);
System.out.println("用户姓名" + this.name);
System.out.println("用户性别" + this.gender);
System.out.println("用户密码" + this.password);
}
}
public class Text {
public static void main(String[] args) {
Student student = new Student();
student.setAge(8);
student.setName("张三");
student.setGender('男');
student.setPassword("123123");
student.show(); } }
static
- static表示静态或全局,可以用来修饰成员变量、成员方法以及代码块;
类中成员变量/方法(非静态)需要访问时,必须依赖于对象(外部访问)
public class User {
//成员变量
public int id;
//成员方法
public void test(){
System.out.println(id);
}
}
public class Test {
public static void main(String[] args) {
User user = new User();
user.id = 100;
user.test();
}
}
- 使用static修饰成员变量/成员方法时,该对象或方法就会独立于该类的任何一个实例对象,访问时就不需要依赖于对象;
public class User {
//静态成员变量
public static int id;
//静态成员方法
public static void test(){
System.out.println(id);
}
}
public class Test {
public static void main(String[] args) {
User.id = 2;
User.test();
}
}
- 总结:
- 非静态成员不属于类,属于每个实例化对象。每个实例化对象都有自己的成员变量,彼此独立,互不影响;
- 静态成员变量属于类,不属于实例化对象。只不过实例化对象可以引用类中的成员变量,由此大家共享。只要一个对象修改成员变量,所有的对象引用全部修改;
- 使用static修饰成员变量时需要注意,静态方法中不能使用this关键字,不能直接访问所属类的实例变量和实例方法;
- 静态方法中不能访问非静态变量,但在非静态方法中可以访问静态变量;
- static除了可以修饰成员变量和成员方法外还可以修饰代码块,被其修饰了的代码块叫做静态代码块;
-
类中的代码块什么时候执行?
当Java程序加载该类时执行,每当Java程序中出现该类的时候,就会执行一次; -
静态代码块什么时候执行?
当Java程序第一次加载该类的时候执行,当Java程序中第一次出现该类的时候执行一次,后面再出现该类就不再执行;
继承
- 继承描述的是类与类之间的一种关系,将类分为父类和子类,子类可以直接获取父类中的所有公有(public)资源(成员变量和方法),是Java 程序提高代码复用性的一种重要方式。
- 一个子类只能有一个直接父类,但是可以有多个间接父类(父类也可以有父类)。
- 之类访问父类
实现了继承关系的父子类,在创建子类对象的时候,会优先创建父类对象,无论子类是通过有参构造还是无参构造来创建对象,父类都是通过无参构造来创建。
子类的成员方法中可以通过 super 关键字调用父类的成员变量和成员方法。
public class Teacher extends People {
public Teacher(){
super(1);
System.out.println("调用了Teacher的无参构造"); }
public Teacher(int i){
super(1);
System.out.println("调用了Teacher的有参构造");
}
}
People 有没有父类?
有,每个 Java 类都会有一个默认的父类 Object,Object 是所有 Java类的根节点,Java 中的所有类(无论是官方 JDK 提供的类还是开发者自定义的类,第三方框架定义的类)都是 Object 的后代(直接子类或者间接子类)
默认父类是通过无参来创建对象的,如何让父类通过有参来创建的?
需要使用 super 关键字,this 用作访问当前类的属性和方法,super用作访问父类的属性和方法。
子类访问权限
访问权限修饰符:public、private、protected、默认(不写)
权限修饰符 | 同一类 | 同一包 | 不同包 | 子类 |
---|---|---|---|---|
public | 可以访问 | 可以访问 | 可以访问 | 可以访问 |
protected | 可以访问 | 可以访问 | 不能访问 | 可以访问 |
默认 | 可以访问 | 可以访问 | 不能访问 | 可以访问(同包) |
private | 可以访问 | 不能访问 | 不能访问 | 不能访问 |
- 包
- Java 中的包是用来管理文件的,一共系统中类非常多,不可避免会出现类名重复的情况,通过设置包的方式来解决这一问题,同一个包中不能出现相同的类名,但是在不同的包中可以出现相同的类名。
- 包的命名规范:包名由小写字母组成,不能以.开头或者结尾,可以包含数字,但是不能以数字开头,如果以数字开头则不是一个包,只是一个文件夹,不能创建 Java 代码。
- 一般命名的话以组织的网络域名方向输出就是包名。
方法重写
- 建立在继承的基础上,子类对父类方法的重新定义并覆盖的操作叫做重写;
- 构造方法不能被重写,方法重写规则:
- 父之类方法名相同;
- 父之类的方法参数列表相同;
- 子类返回值与父类返回值类型相同或是其子类;
- 子类方法的访问权限不能小于父类;
-
访问全县按照作用域从大到小:
- public>protected>默认>private
- 如果父类访问权限为 public,那么子类只能是 public如果父类访问权限为 protected,那么子类可以是public、protected如果父类访问权限为默认,那么子类可以是 public、protected、默认;
- 重写必须建立在继承的基础上,子类只能继承父类的非私有的方法和属性,也就是说父类私有的方法子类压根不能继承,那么也就不存在重写了。
-
方法重写对比方法重载
所在位置 | 方法名 | 参数列表 | 返回值 | 访问权限 | |
---|---|---|---|---|---|
方法(覆盖)重写 | 父之类中 | 相同 | 相同 | 相同或是其子类 | 不能小于父类 |
方法重载 | 同一类中 | 相同 | 不能访问 | 没有要求 | 没有要求 |
多态
- 多态的概念比较抽象,简单解释就是:一个事物在不同时间地点有不同表现形体;
- Java程序中,就是定义一个方法,在具体的生成环境中根据不同的需求呈现出不同的业务逻辑;
- 业务场景:书店的普通会员买书有折扣
public class Member {
public void buyBook(){ }
}
public class OrdinaryMember extends Member {
@Override
public void buyBook() {
System.out.println("普通会员买书9折");
}
}
public class SuperMember extends Member {
@Override
public void buyBook() {
System.out.println("超级会员买书6折");
}
}
public class Cashier {
private Member member;
public void setMember(Member member) {
this.member = member;
}
public void settlement(){
this.member.buyBook();
}
}
public class Text {
public static void main(String[] args) {
Member member = new OrdinaryMember();
Cashier cashier = new Cashier();
cashier.setMember(member);
cashier.settlement();
}
}
- 多态是基于继承/抽象,因为多态最核心的点就是一个事物可以有很多种不同的表现形式。一个对象可以转换为不同类的对象(数据类型的转换),也就是说必须有数据类型转换在前,才可能有多态;
- 引用数据类型转换就是基于继承的;
多态的使用
- 在实际开发中,多态主要有两种表现形式:
- 一种是定义方法时形参为父类,调用方法时传入参数为子类对象;
public class Cashier {
public void settlement(Member member){
member.buyBook();
}
}
public class Text {
public static void main(String[] args) {
Cashier cashier = new Cashier();
OrdinaryMember ordinaryMember = new OrdinaryMember();
cashier.settlement(ordinaryMember);
SuperMember superMember = new SuperMember();
cashier.settlement(superMember); } }
- 另一种是定义方法时返回值类型为父类,调用方法时返回值为子类对象;
public Member getMember(String name){
if(name.equals("ordinaryMember")){
return new OrdinaryMember();
}
if(name.equals("superMember")){
return new SuperMember();
}
return null;
}
Cashier cashier = new Cashier();
System.out.println(cashier.getMember("ordinaryMember"));
System.out.println(cashier.getMember("superMember"));
Member member = new OrdinaryMember();
OrdinaryMember member1 = (OrdinaryMember) new Member();
- 父类引用可以直接指向子类,子类转父类可以自动完成,无需强制转换。向上转型;
- 子类应用不能直接指向父类,父类专子类需要强制完成。向下转型;
抽象
- 如果一个方法没有具体的方法实现(方法体),只有方法的定义,那么这个方法就叫做抽象方法,声明抽象方法时需要添加 abstract 关键字;
- 一旦类种定义了抽象方法,则该类也必须声明为抽象类,需要在类定义处添加 abstract 关键字;
public abstract class Member{
public abstract void buyBook();
}
- 抽象类和普通类的区别就是抽象类不能被实例化,抽象方法和普通方法的区别时抽象方法没有方法体;
- 抽象类中可以没有抽象方法;
public abstract class Member {
public void test(){
}
}
- 但是包含了抽象方法的类一定是抽象类;
public abstract class Member {
public abstract void buyBook();
}
- 可以在抽象类中定义普通方法,但是不能在普通类中定义抽象方法。继承了抽象类的子类必须要重写父类的抽象方法,完成方法的具体实现;
public class OrdinaryMember extends Member {
@Override
public void buyBook() {
System.out.println("9折");
}
}
- 如果子类也是抽象类,可以不用重写父类抽象方法;
public abstract class OrdinaryMember extends Member {
}
- 匿名内部类:匿名内部类就是一个重写了父类抽象方法的子类,只不过我们将它定义在了方法内部,并且没有名字。所以叫匿名内部类;
public class Test {
public static void main(String[] args) {
Member member = new Member() {
@Override
public void buyBook() {
System.out.println("3折");
}
};
}
}