4 面向对象三大特性
4.1 封装Encapsulation
-
该露的露,该藏得藏
程序设计要追求“高内聚低耦合”
。高内聚:类的内部操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用。 -
封装(数据的隐藏)
信息隐藏:就是禁止直接访问 一个对象中 数据的实际表示,而通过操作接口来访问。 -
private属性私有,get/set
封装的优点:
- 提高程序的安全性,保护数据;
- 隐藏代码的实现细节;
- 统一接口;
- 增加系统可维护性
package com.f.oop3Encapsulation;
// 创建员工类
public class Employee {
//属性:字段
String name;
String sex;// 性别
int age;
int seniority;// 工龄
public String getName(){
return name;
}
public void setName(String name){
this.name= name;
}
// 性别
public String getSex() {
return sex;
}
public void setSex(String sex) {
switch (sex){
case "男":
case "man":
this.sex = "男";
break;
default:
this.sex = "女";
}
}
public int getAge(){
return age;
}
public void setAge(int age){
if (age < 0 || age > 120){
this.age = 6;
}else {
this.age = age;
}
}
// 工龄
public int getSeniority() {
return seniority;
}
public void setSeniority(int seniority) {
if (seniority > 52 || seniority < 0){
this.seniority = 0;
}else {
this.seniority = seniority;
}
}
}
package com.f.oop3Encapsulation;
// 调用员工类
public class Application {
public static void main(String[] args) {
Employee emp = new Employee();
emp.setSex("man");
System.out.println(emp.getSex());
emp.setAge(-1);// 不合法
System.out.println(emp.getAge());
}
}
4.2 继承 Inherits
1)继承的本质就是对某一批类的抽象,从而实现对世界更好的建模。
2)extends
的意思是“扩展”。子类是父类的扩展。
3)Java中类只有单继承,没有多继承
4)继承是类和类之间的一种关系。此外还有依赖、组合、聚合等关系。
5)继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示;
6)子类和父类之间应该具有 “(子类) is a (父类)” 的关系;
7)object 类:Java中所有的类,默认直接或间接继承 Object;
4.2.1 super
super 注意点:
- super调用父类的构造方法,必须在构造方法的第一个位置;
- super只能出现在子类的方法或构造方法中;
- super和 this不能同时调用构造方法。
super VS. this:
- 代表对象不同:
this:调用者是当前类;
super:调用者是父类- 前提:
this:没有继承也可以使用;
super:只能在继承的前提下才能使用。- 构造方法:
this():本类的构造方法
super():父类的构造方法
1.Employee 类
public > protected > default > private
属性一般都是私有(private),方法一般是共有(public)
package com.f.oop4JiCheng;
public class Employee /*extends Object*/{
// 私有 属性:字段
private String name;
int money= 10_0000_0000;
// Employee 的无参构造器
public Employee(){
System.out.println("Employee 无参构造器");
}
public String getName(){
return name;
}
public void setName(String name){
this.name= name;
}
public String say(){
return "这里是财务,你有什么事?";
}
}
2.Finance extends Employee
package com.f.oop4JiCheng;
// 财务类
public class Finance extends Employee {
private int money= 10_0000;
/* Finance 的无参构造器*/
public Finance(){
super();// 可以隐藏不写
System.out.println("Finance 的无参构造器");
}
public void test(int money){
//形参中的
System.out.println("形参中的:" + money);
// 本类中的属性
System.out.println("本类中的:" + this.money);
// 父类中的属性
System.out.println("父类中的:" + super.money);
}
}
3.测试
package com.f.oop4JiCheng;
public class Application {
public static void main(String[] args) {
Finance fin = new Finance();
fin.setName("tom");
System.out.println(fin.say());
fin.test(100);
}
}
4.2.2 方法重写
1)为什么需要重写?
- 父类的功能子类不一定需要,或不一定满足;
- 快捷键:Alt + Insert --> Override(重写; 覆盖) 。
2)方法重写(override)(:是指子类对父类的非静态、非私有、非final方法进行重新实现的过程
和属性无关。)–>多态的前提
Java中的方法重写
3)重写:的前提是需要有继承关系,子类重写父类的方法!
- 子类在重写父类方法时,必须与父类方法的原型一致,包括修饰符、返回值类型、方法名和参数列表。
- JDK7以后,被重写的方法的返回值类型可以与父类方法的返回值类型不同,但必须是具有父子关系的类型。
- 重写的方法的访问权限不能比父类方法的访问权限更低,可以更高或相同;public > protected > default > private。
- 父类中被static、private、final修饰的方法不能被重写。
- 抛出的异常:范围可以扩大,但是不能缩小
class Animal {
public void sound() {
System.out.println("Animal makes sound");
}
}
class Dog extends Animal {
@Override
public void sound() {
System.out.println("Dog barks");
}
}
public class Main {
public static void main(String[] args) {
Animal animal = new Animal();
animal.sound(); // 输出:Animal makes sound
Dog dog = new Dog();
dog.sound(); // 输出:Dog barks
}
}
重写总结:子类的方法和父类必须一致,方法体不同;重写只和非静态的方法
有关,与非静态的方法无关。
4.3 多态 Polymorphism
Java多态是面向对象编程中的一个重要概念,它允许我们使用父类的引用变量来引用子类的对象。这样做的好处是可以在不改变代码的情况下,通过改变引用变量的指向来调用不同子类对象的方法。
在Java中,多态性可以通过继承和方法重写来实现。当一个父类引用变量引用一个子类对象时,我们可以通过该引用变量调用子类中重写的方法,而不是父类中的方法。
/*Person是父类,Student和Teacher是子类。通过创建
Person类的引用变量p1和p2,并分别指向Student和Teacher对象,
我们可以调用它们各自重写的mission()方法。*/
class Person {
public void mission() {
System.out.println("执行任务");
}
}
class Student extends Person {
@Override
public void mission() {
System.out.println("学生写作业");
}
}
class Teacher extends Person {
@Override
public void mission() {
System.out.println("教师写教案");
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Student(); // 多态形式,创建对象
p1.mission(); // 输出:学生写作业
Person p2 = new Teacher(); // 多态形式,创建对象
p2.mission(); // 输出:教师写教案
}
}
- 特性:动态编译(运行时才确定类型),可扩展性强;
- 多态:同一方法可以根据发送对象的不同,而采取多种不同的行为方式;
- 一个对象的实际类型是确定的,但可以指向对象的引用类型有很多(一般是父类 或有关系的类);
- 注意:多态是方法的多态,属性没有多态性;
4.3.1 多态存在的条件
- 有继承关系;
- 子类重写父类的方法;
- 父类引用指向子类对象。
4.3.2 多态注意事项:
- 多态是方法的多态,属性没有多态;
- 父类和子类有联系,注意类型转换异常 ClassCastException
- 多态存在条件:继承关系、方法需要重写、
父类引用指向子类对象:Father f1 = new Son();- 不满足多态的情况:
4.1 private修饰的方法:私有方法;
4.2 static修饰的方法:它是属于类,不属于实例;
4.3 final 常量
package com.f.oop5DuoTai;
// 父类:员工
class Employee {
public void say(){
System.out.println("Emp,say()");
}
}
// 子类:财务
class Finance extends Employee{
public void say(){
System.out.println("Fin,say()");
}
public void eat(){
System.out.println("Fin,eat()");
}
}
public class Main {
public static void main(String[] args) {
/* 1.一个对象的实际类型是确定的:
new Employee();// 父类
new Finance();// 子类 */
/* 2.可以指向的引用类型就不确定了*/
// Finance:能调用的方法都是自己的 或者是继承父类的
Finance fin1 = new Finance();
// Employee:父类只能调用子类重写父类的方法,但是不能调用子类独有的方法
Employee emp2 = new Finance();
Object obj3 = new Finance();
/* 对象能执行哪些方法,主要看对象左边的类型,和右边关系不大*/
fin1.eat();// 子类重写了父类的方法,执行子类的方法
((Finance) emp2).eat();
}
}
4.3.3 instanceof
判断对象类型
instanceof
的作用1:判断一个对象是什么类型;
boolean result = obj instanceof Class
其中,obj 是一个对象,Class 表示一个类或接口。obj 是 class 类(或接口)的实例或者子类实例时,结果 result 返回 true,否则返回 false。
示例代码:
package com.f.oop5DuoTai;
//父类:员工
class Employee {
public void say(){
System.out.println("Emp,say()");
}
}
//子类:开发部
class Development extends Employee{
}
//子类:财务
class Finance extends Employee{
}
类之间的关系:
Object > String
Object > Employee > Development
Object > Employee > Finance
package com.f.oop5DuoTai;
public class Application {
public static void main(String[] args) {
Object obj = new Finance();
//判断他们是否有关系
System.out.println(obj instanceof Finance);// 结果,true
System.out.println(obj instanceof Employee);// 结果,true
System.out.println(obj instanceof Object);// 结果,true
System.out.println(obj instanceof Development);// 结果,false
System.out.println(obj instanceof String);// 结果,false
System.out.println("----------------");
Employee emp = new Finance();
System.out.println(emp instanceof Finance);// 结果,true
System.out.println(emp instanceof Employee);// 结果,true
System.out.println(emp instanceof Object);// 结果,true
System.out.println(emp instanceof Development);// 结果,false
//System.out.println(emp instanceof String);// 编译报错
System.out.println("============");
Finance fin = new Finance();
System.out.println(fin instanceof Finance);// 结果,true
System.out.println(fin instanceof Employee);// 结果,true
System.out.println(fin instanceof Object);// 结果,true
//System.out.println(fin instanceof Development);// 结果,编译报错
//System.out.println(emp instanceof String);// 结果,编译报错
/* 总结:如果有关系就能通过编译
System.out.println(x instanceof Y);
*/
}
}
要想了解更多看这篇文章:Java instanceof关键字详解
4.3.4 类型转换;
是引用类型的(父类和子类之间的)类型转换
package com.f.oop5DuoTai;
//子类:财务
class Finance extends Employee{
public void go(){
System.out.println("Finance.go()");
}
}
//父类:员工
class Employee {
public void run(){
System.out.println("Employee.run()");
}
}
/**
* Polymorphism 多态
* 类型之间的转化:父类 和子类 之间
*/
public class Application {
public static void main(String[] args) {
/** 1.父类转换为子类*/
Employee emp = new Finance();
// 强制转换,方法1
Finance fin = (Finance) emp;
fin.go();// 结果,Finance.go()
// 强制转换,方法2
((Finance) emp).go();// 结果,Finance.go()
System.out.println("---------");
/** 2.子类转换为父类*/
Finance finance = new Finance();
//子类调用自己的方法
finance.go();// 结果,Finance.go()
//自动转换1 ;父类的引用指向子类的对象
Employee employee = finance;
employee.run();//Employee.run()
//自动转换2;子类转型成功后 会丢失一些(独有的)方法
finance.run();// 结果,Employee.run()
}
}
5 Static关键字
5.1 静态变量和静态方法
package com.f.oop6Static;
public class Student {
//静态变量,全局都可以使用。多线程 中使用的较多!
private static int age;
//非静态变量
private double score;
//非静态方法 可以调用 静态方法
public void run(){
say();
}
/*静态方法只能 new出实例后才能调用非静态方法*/
public static void say(){
new Student().run();
}
}
5.2 静态代码块
执行顺序:静态代码块、匿名代码块、无参构造器;
package com.f.oop6Static;
public class Person {
/**1.静态代码块,加载类的时候执行,且永久只执行一次*/
static {
System.out.println("静态代码块");
}
/**2.匿名代码块,创建类的时候 一起创建;作用:赋初始值*/
{
System.out.println("匿名代码块");
}
/**3.无参构造器,创建类的时候 创建,但在匿名代码块之后*/
public Person() {
System.out.println("无参构造器");
}
public static void main(String[] args) {
System.out.println("----");
Person person = new Person();
System.out.println("=====");
Person per = new Person();
}
}
5.3 final修饰符
final修饰类时,该类不可被继承,如 Math类。
import java.util.Random;
public final class Math {
private Math() {}
public static final double PI = 3.14159265358979323846;
public static double tan(double a) {
return StrictMath.tan(a); // default impl. delegates to StrictMath
}
private static final class RandomNumberGeneratorHolder {
static final Random randomNumberGenerator = new Random();
}
public static double random() {
return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
}
//......
}