文章目录
十八.面向对象编程(中级)
IDE快捷键(修改过的)
操作 | 快捷键 |
---|---|
删除当前行 | Ctrl + D |
复制当前行 | Ctrl + Alt + 下 |
注释 | Ctrl + / |
格式化代码 | Ctrl + shift + L |
设置 | Ctrl + Alt + S |
生成构造器 | Alt + Insert |
查看类的层级关系 | Ctrl + H |
定位到这个类的方法 | Ctrl + B |
包
包的三大作用:
- 区分相同名字的类
- 当类很多时,可以更好的管理类 [ 看API文档 ]
- 控制访问范围
package com.use;
import com.xiaoming.Dog;
public class Test {
public static void main(String[] args) {
Dog dog1 = new Dog();
System.out.println(dog1);
com.xiaoqiang.Dog dog2 = new com.xiaoqiang.Dog();
System.out.println(dog2);
}
}
包的规则:
- 只能包含数字字母,下划线,小圆点,但是不能用数字开头,不能是关键字或者保留字
- 一般是小写字母+小圆点
- com.公司名.项目名.业务模块
java中常用的包
- java.lang.*//基本包,默认引入,不需要再引入
- java.util.*//util包,系统提供的工具包,工具类,使用Scanner
- java.net.*//网络包,网络开发
- java.awt.*//java的界面开发,GUI
建议导入包的时候需要哪个导入哪个,不要直接导入*
一个类中最多只有一个package
访问修饰符
java提供了四种访问修饰符
- 公开级别:public公开类
- 受保护级别:protected保护类
- 默认级别:没有修饰符,向同一个包的公开类
- 私有类别:peivate修饰,只有类本身可以访问,其余的不能访问。
访问级别 | 访问修饰符 | 同类 | 同包 | 子类 | 不同包 |
---|---|---|---|---|---|
公开 | public | true | true | true | true |
受保护 | protected | true | true | true | false |
默认 | 没有修饰符 | true | true | false | false |
私有 | private | true | false | false | false |
使用的注意事项:
- 修饰符可以用来修饰类中的属性,成员方法以及类
- 只有默认的和public才能修饰类,并且遵循上述访问权限的特点
- 成员方法的访问规则和属性完全一样。
封装
封装就是把抽象的数据(属性)和对数据的操作(方法)封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作(方法),才能对数据进行操作。
封装的好处:
- 可以隐藏实现的细节:方法(连接数据库)< – 调用(传入参数)
- 可以对数据进行验证,保证安全合理
封装的实现
- 将属性进行私有化(不能直接修改属性)
- 提供一个公共的(public)set方法,用于对属性判断并赋值
- 提供一个公共的(public)get方法,用于获取属性的值
idea快捷键:alt + insert 然后就setter and getter
继承
继承的基本语法
class 子类 extens 父类{
}
- 子类会自动拥有父类定义的属性和方法
- 父类又叫做超类,基类
- 子类又叫做派生类
最主要的是能够解决代码的冗余问题
子类继承了所有的属性和方法,但是私有属性和方法不能在子类直接访问,要通过访问公共的方法去访问。
子类必须调用父类的构造器,完成父类的初始化,父类先被调用,子类后被调用。
当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,必须在子类的构造器中用super去指定父类的哪个构造器完成对父类的初始化工作,否则编译不会通过。
package com.use.encap.improve;
public class improve01 extends improve{
public improve01() {
//super();//默认使用了super
super("jack",123);
//this();//这里不能使用this();
System.out.println("improve01");
}
public improve01(String name, int age){
super("Tom",13);
System.out.println("父类被调用");
}
public void say01(){
System.out.println(n1 + n2 + n3 );//n4因为是私有的,所以不能访问。
}
public static void main(String[] args) {
improve01 aaa = new improve01();
aaa.say01();
}
}
package com.use.encap.improve;
public class improve {
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
public improve(String name ,int age) {//无参构造器
System.out.println("improve");
}
public void test001(){
System.out.println("100");
}
protected void test002(){
System.out.println("200");
}
void test003(){
System.out.println("300");
}
private void test004(){
System.out.println("400");
}
}
如果希望指定去调用父类的某个构造器,则显示的调用一下:super(参数列表)
super在使用时,需要放在构造器的第一行
super()和this()都只能放在构造器的第一行,因此这两个方法不能共存在一个构造器。
java中所有类都是Object类的子类,Object是所有类的基类。
父类构造器的调用不限于直接父类,将一致往上追溯到Object(顶级父类)
子类最多只能继承一个父类(直接继承),java中是单继承机制。
不能滥用继承,子类和父类之间必须满足is - a的逻辑关系。
Person is a Music?
package com.use.encap.homework01;
public class homework01 {
//编写类,其中包含CPU,内存,硬盘等属性,getDetails方法用于返回类的详细信息
//编写PC子类,继承该类,添加特有属性品牌brand
//编写Notepad子类,继承该类,添加特有属性颜色color
//编写Test类,在main方法中创建PC和Notepad对象,分别给对象中特有的属性赋值,以及对该类继承的属性赋值,并使用方法打印输出信息。
private String CPU;
private int memory;
private int disk;
public homework01(String CPU,int memory,int disk){
this.CPU = CPU;
this.memory = memory;
this.disk = disk;
}
public String getCPU() {
return CPU;
}
public void setCPU(String CPU) {
this.CPU = CPU;
}
public int getMemory() {
return memory;
}
public void setMemory(int memory) {
this.memory = memory;
}
public int getDisk() {
return disk;
}
public void setDisk(int disk) {
this.disk = disk;
}
public String Details(){
return "CPU:" + CPU + " " + "memory:" + memory + " " + "disk:" + disk + " ";
}
}
package com.use.encap.homework01;
import java.sql.SQLOutput;
public class Notepad extends homework01{
private String color;
public Notepad(String CPU, int memory, int disk,String color) {
super(CPU, memory, disk);
this.color = color;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public void pinfo(){
System.out.println("输出的结果为:" + Details() + "color:" + color);
}
}
package com.use.encap.homework01;
public class PC extends homework01 {
private String brand;
public PC(String CPU, int memory, int disk, String brand) {
super(CPU, memory, disk);
this.brand = brand;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public void pinfo(){
System.out.println("输出的结果为:" + Details() + "brand:" + brand);
}
}
package com.use.encap.homework01;
public class main {
public static void main(String[] args) {
Notepad aaa = new Notepad("intel",32,500,"bule");
PC bbb = new PC("intel",32,600,"华为");
aaa.pinfo();
bbb.pinfo();
}
}
Super关键字
super代表父类的引用,用于访问父类的属性,方法,构造器。
可以访问父类的属性,但是不能访问父类的private属性
可以访问父类的方法,但是不能访问父类的peivate方法
访问父类的构造器:只能放在构造器的第一句,只能出现一句话。
调用父类的构造器的好处(分工明确,父类属性由父类初始化,子类的属性由子类初始化)
当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须访问super。如果没有重名,通过super访问是一样的效果。
super 的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以是使用super去访问爷爷类的成员,如果多个基类中都有同名的成员,使用super访问遵循就近原则。如果父类中没有该成员名,则继续在爷爷类中进行寻找。当然也是要遵循访问权限的原则。
区别 | this | super |
---|---|---|
访问属性 | 访问本类中的属性,如果本类中没有此属性,则从父类中继续查找 | 从父类开始查找属性 |
调用方法 | 访问本类中的方法,如果本类没有此方法咋从父类中继续查找 | 从父类开始查找方法 |
调用构造器 | 调用本类构造器,必须放在构造器的首行 | 调用父类构造器,必须放在子类构造器的首行 |
特殊 | 表示当前对象 | 子类中访问父类对象 |
方法重写/(覆盖)
就是说子类中有一个方法,和父类的某个方法的名称,返回类型,参数一致,就说这个子类的方法覆盖了父类的方法。
方法重写的细节:
- 子类的方法的参数名称,方法名称要和父类方法的参数,方法名称完全一致
- 子类方法的返回类型和父类方法的返回类型一致,或者父类返回类型的子类
- 子类方法不能缩小父类方法的访问权限
名称 | 发生范围 | 方法名 | 参数列表 | 返回类型 | 修饰符 |
---|---|---|---|---|---|
重载(overload) | 本类 | 必须一样 | 类型,个数,或者顺序至少有一个不同 | 无需求 | 无要求 |
重写(override) | 父子类 | 必须一样 | 相同 | 子类重写的方法,返回的类型和父类返回的类型是一致的,或者说是其子类 | 子类方法不能缩小父类方法的范围 |
package com.use.encap.homework02;
public class Person {
//编写一个Person类,包括属性/private(name,age),构造器,方法say(返回自我介绍的字符串)
//编写一个Student类,继承Person类,增加id,score属性/private,以及构造器,定义say方法(返回自我介绍的信息)
//在main中,分别创建Person和Student对象,调用say方法输出自我介绍。
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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 say(){
return "name:" + name + " " + " age:" + age + " ";
}
}
package com.use.encap.homework02;
public class Student extends Person{
private int id;
private double score;
public Student(String name, int age,int id,double score) {
super(name, age);//调用父类构造器
this.id = id;
this.score = score;
}
public String say(){
return super.say() + "id:" + id + " " + "score:" + score + " ";
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
}
package com.use.encap.homework02;
public class main {
public static void main(String[] args) {
Person aaa = new Person("Tom",13);
Student bbb = new Student("jack",14,5,37);
System.out.println(aaa.say());
System.out.println(bbb.say());
}
}
多态
可以提高代码的复用性,方便代码的维护,建立在封装和继承的基础之上的。
对象的多态
- 一个对象的编译里欸选哪个和运行
- 编译类型在定义对象时,就确定了,不能改变
- 运行类型是可以改变的
- 编译类型要看等号的左边,运行类型要看等号的右边
父类的引用指向子类的对象
在编译阶段,能调用那些成员,是由编译类型决定的。
可以调用父类的所有成员,但是不能调用子类的特有成员
Animal animal = new Cat();
Cat cat = (Cat) animal;
属性没有重写这一个说,属性的值看编译类型
属性看编译,方法看运行
java的动态绑定机制
- 当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定(和运行类型绑定,执行改方法的时候,首先找到该方法的运行类型,看看是否能够找到,若找不到就到父类进行寻找。)
- 当调用对象属性时,没有动态绑定机制,哪里声明哪里使用。
java动态数组
package com.use.encap.pro02;
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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 say(){
return name + "\t" + age + "\t";
}
}
package com.use.encap.pro02;
public class student extends Person{
private double score;
public student(String name, int age,double score) {
super(name, age);
this.score = score;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public String say() {
return super.say() + "score=" + score;
}
public void study(){
System.out.println("学生:" + getName());
}
}
package com.use.encap.pro02;
public class teacher extends Person{
private double salary;
public teacher(String name, int age, double salary) {
super(name, age);
this.salary = salary;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String say() {
return super.say() + "salary=" + salary;
}
public void teacher(){
System.out.println("老师:" + getName());
}
}
package com.use.encap.pro02;
public class main {
public static void main(String[] args) {
Person[] persons = new Person[5];
persons[0] = new Person("jack",14);
persons[1] = new student("name01",15,17.00);
persons[2] = new teacher("name02",17,97.00);
persons[3] = new teacher("name02",17,97.00);
persons[4] = new teacher("name02",17,97.00);
for (int i = 0; i < persons.length; i++){
System.out.println(persons[i].say());
if (persons[i] instanceof student){
student student = (student)persons[i];
student.study();
} else if (persons[i] instanceof teacher) {
teacher teacher = (teacher)persons[i];
teacher.teacher();
}else {
System.out.println("您的类型有误,请检察");
}
}
}
}
package com.use.encap.pr03;
public class Employee {
private String name;
private double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public double getAnnual(){
return 12 * salary;
}
}
package com.use.encap.pr03;
public class Manager extends Employee{
private double bonus;
public Manager(String name, double salary, double bonus) {
super(name, salary);
this.bonus = bonus;
}
public double getBonus() {
return bonus;
}
public void setBonus(double bonus) {
this.bonus = bonus;
}
public void manage(){
System.out.println("经理:" + getName() + " is managing");
}
@Override
public double getAnnual() {
return super.getAnnual() + bonus;
}
}
package com.use.encap.pr03;
public class worker extends Employee{
public worker(String name, double salary) {
super(name, salary);
}
public void work(){
System.out.println("普通员工:" + getName() + " is working");
}
@Override
public double getAnnual() {//因为普通的员工没有奖金,所以直接调用就好
return super.getAnnual();
}
}
package com.use.encap.pr03;
import javafx.concurrent.Worker;
public class Test {
public void showEmpAnnual(Employee e) {
System.out.println(e.getAnnual());
}
public void testwork(Employee e) {
if (e instanceof worker) {
((worker) e).work();//向下转型操作
} else if (e instanceof Manager) {
((Manager) e).manage();//向下转型操作
} else {
System.out.println("不做处理!!!");
}
}
public static void main(String[] args) {
worker Tom = new worker("Tom", 13577);
Manager Jack = new Manager("Jack", 23445, 1466);
Test test = new Test();
test.showEmpAnnual(Tom);
test.showEmpAnnual(Jack);
test.testwork(Tom);
test.testwork(Jack);
}
}
Object类详解
equals和==的对比
- ==既可以判断基本类型,又可以判断引用类型。
- ==如果判断基本类型,判断的是数值是否相等。
- ==如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象。
- equals只能判断引用类型,equals指的是值是否相等。
- equals在比较String,Date,ArratList等类的时候,进行了方法的重写,不是进行比较地址,而是进行比较两者的内容是否相等。
Hash_Code
- 提高具有哈希结构的容器的效率。
- 两个引用,如果指向的是同一个对象,则哈希值肯定是一样的。
- 两个引用,如果指向的是不同对象,则哈希值是不一样的。
- 哈希值主要根据地址号来的,不能完全将哈希值等价于地址。
- 在集合中,如果hash需要的话,也会进行重写。
to_String
- 默认返回:全类名 + @ + 哈希值的十六进制
- 重写toString方法,打印对象或拼接对象时,都会自动调用该对象的toString形式。
- 当直接输入一个对象时,toString方法会被默认的调用。(System.out.println(object))
finalize
(平常几乎不会用)
- 当对象被回收时,系统自动调用该对象的finalize方法,子类可以重写该类方法,做一些释放资源的操作
- 什么时候被回收:当某个对象没有任何引用时,则JVM就会认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象之前,会先调用finalize方法。
- 垃圾回收机制的调用,是由系统来决定的(有自己的GC算法),也可以通过System.gc()主动触发垃圾回收机制。
如果不重写finalize,默认调用object中的finalize
调用垃圾回收方法并会不会造成阻塞。
断点调试
练习
//1.定义一个Person类{name,age,job},初始化Person对象数组,有3个person,并按照age从大到小进行排序,使用冒泡排序。
package com.use.encap.homework03;
import com.use.encap.pro02.Person;
class person {
private String name;
private int age;
private String job;
public person(String name, int age, String job) {
this.name = name;
this.age = age;
this.job = job;
}
@Override //这里重写了toString方法下面输出的结果才不是类名
public String toString() {
return "person{" +
"name='" + name + '\'' +
", age=" + age +
", job='" + job + '\'' +
'}';
}
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 getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
}
public class homework {
public static void main(String[] args) {
person[] pp = new person[3];
pp[0] = new person("jack", 13, "good");
pp[1] = new person("rose", 15, "nice");
pp[2] = new person("mack", 50, "bad");
for (int i = 0; i < pp.length; i++) {
System.out.println(pp[i]); //输出的是默认对象的toString()
}
person bb = null;
for (int i = 0; i < pp.length - 1; i++) {
for (int j = i; j < pp.length - 1 - i; j++) {
if (pp[i].getAge() < pp[i + 1].getAge()) {
bb = pp[i];
pp[i] = pp[i + 1];
pp[i + 1] = pp[i];
}
}
}
System.out.println("=========================");
System.out.println("排序之后的结果如下:");
for (int i = 0; i < pp.length; i++) {
System.out.println(pp[i]); //输出的是默认对象的toString()
}
}
}
//2.要求有属性“姓名name”,"年龄age","职称post","基本工资salary"
//编写业务方法,introduce(),实现输出一个教师的信息
//编写教师类的三个子类:教师类(Professor),副教授类,讲师类。工资级别分为:教授1.3,副教授1.2,讲师类1.1,在三个子类中都重写introduce()方法
//定义并初始化一个老师对象,调用业务方法,实现对象基本信息的打印功能。
package com.use.encap.homework04;
public class teacher {
private String name;
private int age;
private String post;
private double salary;
private double grade;
public void introduce() {
System.out.println("name:" + name + "\t" + "age:" + age + "\t" + "post:" + post + "\t" + "salary:" + salary + "\t");
}
public teacher(String name, int age, String post, double salary,double grade) {
this.name = name;
this.age = age;
this.post = post;
this.salary = salary;
this.grade = grade;
}
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 getPost() {
return post;
}
public void setPost(String post) {
this.post = post;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public double getGrade() {
return grade;
}
public void setGrade(double grade) {
this.grade = grade;
}
}
package com.use.encap.homework04;
public class professor extends teacher{
public professor(String name, int age, String post, double salary,double grade) {
super(name, age, post, salary,grade);
}
@Override
public void introduce() {
System.out.println("这是教授类");
super.introduce();
}
}
package com.use.encap.homework04;
public class main {
public static void main(String[] args) {
professor professor = new professor("狗子",13,"高级职称",17280,1.3);
professor.introduce();
}
}
//3.通过继承实现员工工资核算打印功能
//父类:员工类
//子类:部门经理类,普通员工
//部门经理工资 = 1000 + 单日工资 * 天数 * 等级(1.2)
//普通员工工资 = 单日工资 * 天数 * 等级(1.0)
//员工属性:姓名,单日工资,工作天数
//员工方法(打印工资)
//普遍员工及部门经理都是员工子类,需要重写打印工资方法
//定义并初始化普通员工对象,调用打印工资 方法输出工资,定义并初始化部门经理对象,调用打印工资方法输出工资
package com.use.encap.homework05;
public class Employee {
private String name;
private double daysal;
private int workdays;
private double grade;
public void printsal() {
System.out.println(name + "工资:" + daysal * workdays * grade);
}
public Employee(String name, double daysal, int workdays, double grade) {
this.name = name;
this.daysal = daysal;
this.workdays = workdays;
this.grade = grade;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getDaysal() {
return daysal;
}
public void setDaysal(double daysal) {
this.daysal = daysal;
}
public int getWorkdays() {
return workdays;
}
public void setWorkdays(int workdays) {
this.workdays = workdays;
}
public double getGrade() {
return grade;
}
public void setGrade(double grade) {
this.grade = grade;
}
}
package com.use.encap.homework05;
public class manager extends Employee{
private double bouns;
//经理的奖金并不是确定的,所以子啊构造器中不给bonus
public manager(String name, double daysal, int workdays, double grade) {
super(name, daysal, workdays, grade);
}
public double getBouns() {
return bouns;
}
public void setBouns(double bouns) {
this.bouns = bouns;
}
@Override
public void printsal() {
//因为经理的计算方式和Emplee不一样,所以要进行重写
System.out.println("经理:" + getName() + "的工资是:" + (bouns + getDaysal() * getWorkdays() * getGrade()));
}
}
package com.use.encap.homework05;
public class worker extends Employee{
public worker(String name, double daysal, int workdays, double grade) {
super(name, daysal, workdays, grade);
}
@Override
public void printsal() {
super.printsal();
}
}
package com.use.encap.homework05;
public class main {
public static void main(String[] args) {
manager manager = new manager("狗子", 100, 20, 1.2);
manager.setBouns(1000);
manager.printsal();
worker worker = new worker("狗子1",100,20,1.1);
worker.printsal();
}
}
//4.定义类
package com.use.encap.homework06;
public class Employee {
private String name;
private double sal;
public Employee(String name, double sal) {
this.name = name;
this.sal = sal;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSal() {
return sal;
}
public void setSal(double sal) {
this.sal = sal;
}
public void printsal() {
System.out.println(name + "年工资是:" + (sal * 12));
}
}
package com.use.encap.homework06;
public class worker extends Employee{
//工人,农民,服务员只有基本工资
public worker(String name, double sal) {
super(name, sal);
}
@Override
public void printsal() {
System.out.println("工人");
super.printsal();
}
}
package com.use.encap.homework06;
public class main {
public static void main(String[] args) {
worker jack = new worker("jack",1000);
jack.printsal();
}
}