07面向对象(中级)包、访问修饰符、面向对象三大特征(封装、继承、多态)、super、方法重写

面向对象

1.区分相同名字的类
2.当类很多时,可以很好的管理类
3.控制访问范围

包的基本语法:

1.package关键字,表示打包
2.com.hspedu:表示包名

包的本质分析(原理):

包的本质 实际上就是创建不同的文件夹来保存类文件

包的命名:

命名规则:
只能包含数字、字母、下划线、小圆点,但是不能用数字开头,不能是关键字或保留字
demo。class.exec1//错误出现关键字class
demo.12a//错误数字在开头
demo.ab12.oa//正确

命名规范:

一般是小写+小圆点一般是com.公司名.项目名.业务模块名
比如:com.slz.oa.model;
com.sina.crm.user//用户模块
com.sina.crm.order//订单模块
com.sina.crm.utils//工具类

注意事项和使用细节:

1.package的作用是声明当前类所在的包,需要放在类的最上面,一个类中最多只有一句Package。
2.impore指令位置放在package的下面,在类定义前面,可以有多句且没有顺序要求

访问修饰符

基本介绍:

java提供四种访问控制修饰符号,用于控制方法和属性(成员变量)的访问权限(范围):
1.公开级别:用public修饰,对外公开
2.受保护级别:用protected修饰,对子类和同一个包中的类公开
3.默认级别:没有修饰符号,向同一个包的类公开
4.私有级别:用private修饰,只有类本身可以访问,不对外公开

4中访问修饰符的访问范围:

访问级别 访问控制修饰符 同类 同包 子类 不同包
公开 public √ √ √ √
受保护 protected √ √ √ X
默认 没有修饰符 √ √ X X
私有 private √ X X X
使用的注意事项:
1.修饰符可以用来修饰类中的属性,成员方法以及类
2.只有默认的和public才能修饰类!,并且遵循上述访问权限的特点
3.因
4.成员方法的访问规则和属于完全一样

面向对象编程三大特点:

基本介绍:

面向对象编程三大特征:封装、继承和多态。

封装:

基本介绍:

封装(encapsulation)就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作[方法],才能对数据进行操作

封装的理解和好处:

1.隐藏实现细节:方法(连接数据库)←调用(传入参数)
2.可以对数据进行验证,保证安全合理
Dog{name.age}
Dog d = new Dog();
d.name = "xiaohei";
d.age = 120;

封装的实现步骤:

1.将属性私有化(不能直接修改属性)
2.提供一个公共的set方法,用于对属性判断并赋值
public void setXxx(类型 参数名){
//加入数据验证的业务逻辑
属性 = 参数名;
}
3.提供一个公共的get方法,用于获取属性的值
public XX getXxx(){//权限判断
return xx;
}

案例:

不能随便查看人的年龄,工资等隐私,并对设置的年龄进行合理的验证。年龄合理就设置,否则给默认。年龄必须在1120,年龄、工资不能直接查看,name的长度在26字符直接。

练习:

创建程序,在其中定义两个类:Account和AccountTest类体会java的封装性
1.Account类要求具有属性:姓名(长度为2位3位或4位)、余额(必须>20)、密码(必须是6位),如果不满足,则给出提示信息,并给默认值
2.通过setXxx的方法给Account的属性赋值。
3.在AccountTest中测试

继承:

继承带来的便利:

1.代码的复用性提高了
2.代码的扩展性和维护性提高了

基本介绍:

继承可以解决代码复用,让我们的编程更加靠近人类思维。当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,索引的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类即可

基本语法:

class 子类 extends 父类{
}
1.子类就会自动拥有父类定义的属性和方法
2.父类又叫超类,基类
3.子类又叫派生类

注意事项和使用细节:

1.子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类直接访问,要通过公共的方法去访问
2.子类必须调用父类的构造器,完成父类的初始化
3.当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中庸super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不通过
4.如果希望指定去调用父类的某个构造器,则显示的调用一下:(super(参数列表))
5.super在使用时,必须放在构造器第一行(super只能在构造器中使用)
6.super()和this()都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
7.java所有类都是Object类的子类
8.父类构造器的调用不限于直接父类!将一直往上追溯直到Object类(顶级父类)
9.子类最多只能继承一个父类(指直接继承),即java中时单继承机制。
10.不能滥用继承,子类和父类必须满足is-a的逻辑关系

练习:

1.class A{
A(){System.out.println("a")}
A(String name){System.out.println("a name");}
}
class B extends A{
B(){this("abc");System.out.println("b");}
B(String name){super();System.out.println("b name");}
}
main中:B b = new B();会输出什么?a,b name ,b

2.编写Computer类,包含CPU、内存、硬盘等属性,getDetails方法用于返回Computer的详细信息
编写PC子类,继承Computer类,添加特有属性[品牌brand]
编写NotePad子类,继承Computer类,添加特有属性[演示color]
编写Test类,在main方法中创建PC和NotePad对象,分别给对象中特有的属性赋值,以及从Computer类继承的属性赋值,并使用方法并打印输出信息。

super:

基本介绍:

super代表父类的引用,用于访问父类的属性、方法、构造器

基本语法:

1.访问父类的属性,但不能访问父类的private属性:super.属性名
2.访问父类的方法,不能访问父类的private方法:super.方法名(参数列表);
3.访问父类的构造器:spuer(参数列表);只能放在构造器的第一句,只能出现一句

super给程序带来的便利/细节:

1.调用父类的构造器的好处(分工明确,父类属性由父类初始化,子类的属性由子类初始化)
2.当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过spuer。如果没有重名,使用spuer、this、直接访问时一样的效果
1)this.方法名()先找本类:有就调用,没有就找父类.如果有并可以调用,则调用
2)spuer.方法名()先找父类,其它规则一样
3.spuer的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;如果多个基类中都有同名的成员,使用super访问遵循就近原则。

方法重写:

基本介绍:

方法覆盖(重写)就是子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的那个方法。

注意事项和使用细节:

方法重写也叫方法覆盖,需要满足以下条件:
1.子类的方法的形参列表,方法名称,要和父类方法的形参列表,方法名称完全一致。
2.子类方法的返回类型和父类方法返回类型一样,或者是父类返回类型的子类比如父类返回类型是Object,子类方法返回类型是String
3.子类方法不能缩小父类方法的访问权限

重载和重写的对比

3.子类方法不能缩小父类方法的访问权限

多态:

基本介绍:

方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。

方法的多态:

重写和重载就体现多态

对象的多态:

1.一个对象的编译类型和运行类型可以不一致
2.编译类型在定义对象时就确定了,不能改变
3.运行类型是可以变化的
4.编译类型看定义时 = 号 的左边,运行类型看 = 号的右边

注意事项和使用细节:

多态的前提是:两个对象(类)存在继承关系

多态的向上转型:

1.本质:父类的引用指向了子类的对象
2.语法:父类类型 引用名 = new 子类类型();
3.特点:编译类型看左边,运行类型看右边。可以调用父类中的所有成员(需遵守访问权限),不能调用子类中特有成员;最终运行效果看子类的具体实现!

多态的向下转型:

1.语法:子类类型 引用名 = (子类类型) 父类引用
2.只能强转父类的引用,不能强转父类的对象
3.要求父类的引用必须指向的是当前目标类型的对象
4.当向下转型后,可以调用子类类型中所有的成员

多态注意事项和细节:

属性没有重写之说!属性的值看编译类型
instanceOf比较操作符,用于判断对象的运行类型是否为XX类型或XX类型的子类型

练习:

1、double d = 13.4;对
long l = (long)d;对
System.out.println(l);13
int i = 5;对
boolean b = (boolean)i;错
Object obj = "hello";对,向上转型
String objStr = (String)obj;对,向下转型
System.out.println(objStr);hello
Object objPri = new Integer(5);对,向上转型
String str = (String)objPri;错,指向Intege的父类引用,转成String
Integer str1 = (Integer)objPri;对,向下转型

2、class Base{
int count = 10;
public void display(){
System.out.println(this.count);
}
}
class Sub extends Base{
int count = 20;
public void display(){
System.out.println(this.count);
}
}
public class Exercise{
public static void main(String[] args){
Sub s = new Sub();
System.out.println(s.count);20
s.display();20
Base b = s;
System.out.println(b == s);对的
System.out.println(b.count);10,属性看编译类型
b.display();20方法看运行类型
}
}

java的动态绑定机制:

Java重要特性:动态绑定机制
1.当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
2.当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用

多态的应用:

1、多态数组:数组的定义类型为父类类型,里面保存的实际元素类型为子类类型
2、多态参数:方法定义的形参类型为父类类型,实参类型允许为子类类型

运算符:

==运算符:

1.:既可以判断基本类型,又可以判断引用类型
2.
:如果判断基本类型,判断的是值是否相等。
3.==:如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象。

equals方法:

4.equals:是Object类中的方法,只能判断引用类型。
5.默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等。

hashCode方法:

1.提高具有哈希结构的容器额效率!
2.两个引用,如果指向的是同一个对象,则哈希值肯定是一样的。
3.两个引用,如果指向的是不同对象,则哈希值也不一样。
4.哈希值主要根据地址号来的,不能完全将哈希值等价于地址

toString方法:

基本介绍:
默认返回:全类名+@+哈希值的十六进制,[查看Object的toString方法]子类往往重写toString方法,用于返回对象的属性
getClass().getName()+"@"+Integer.toHexString(hashCode());
重写toString方法,打印对象或拼接对象时,都会自动调用该对象的toString形式。
当直接输出一个对象时,toString方法会被默认的调用

finalize方法:

1.当对象被回收时,系统自动调用该对象的finalize方法。子类可以重写该方法,做一些释放资源的操作。
2.什么时候被回收:当某个对象没有任何引用时,则jvm就认为这个对象时一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用finalize方法。
3.垃圾回收机制的调用,是由系统来决定,也可以通过System.gc()主动触发垃圾回收机制

作业:

1.定义一个Person类{name,age,job},初始化Person对象数组,有三个person对象,按照age从大到小排序,使用冒泡排序
public static void main(String[] args) {
Person[] people = new Person[3];
people[0] = new Person("hei", 20, "初级工程师");
people[1] = new Person("baide", 30, "中级工程师");
people[2] = new Person("hang", 40, "高级工程师");
//输出数组
for (int i = 0; i < people.length; i++) {
System.out.println(people[i]);//默认对象的.toString()
}
System.out.println("");
//冒泡
Person tmp = null;//用于交换
for (int i = 0; i < people.length - 1; i++) {
for (int j = 0; j < people.length - 1 - i; j++) {
//并按照age从小到大进行排序,如果前面人的age<后面人的年龄,就交换
if(people[i].getAge()>people[i+1].getAge()){
tmp = people[i];
people[i] = people[i + 1];
people[i + 1] = tmp;
}
//按照name长度从小到大进行排序
if(people[i].getName().length()>people[i+1].getName().length()){
tmp = people[i];
people[i] = people[i + 1];
people[i + 1] = tmp;
}
}
}
for (int i = 0; i < people.length; i++) {
System.out.println(people[i]);//默认对象的.toString()
}
}
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;
}
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 String toString() {
return "Person{" +
"name='" + name + ''' +
", age=" + age +
", job='" + job + ''' +
'}';
}
}
2、写出四种访问修饰符和各自的访问权限
本类 同包 子类 不同包
public √ √ √ √
protected √ √ √ x
默认 √ √ X X
private √ X X X

3、编写老师类
1要求有属性"姓名name","年龄age","职称post","基本工资salary"
2编写业务方法,introduce(),实现输出一个教师的信息
3编写教师类的三个子类:教授类(Professor)、副教授类、讲师类。工资级别分别为:教授1.3、副教授为1.2、讲师类1.1.在三个子类里面重写父类introduce()方法
4定义并初始化一个老师对象,调用业务方法,实现对象基本信息的后台打印。

4、通过继承实现员工工资核算打印功能:
父类:员工类
子类:部门经理类、普通员工类
1部门经理工资=1000+单日工资天数等级(1.2)→奖金+基本工资
2普通员工工资=单日工资天数等级(1.0);
3员工属性:姓名,单日工资,工作天数
4员工方法(打印工资)
5普通员工及部门经理都是员工子类,需要重写打印工资方法。
6定义并初始化普通员工对象,调用打印工资方法输入工资,定义并初始化部门经理对象,调用打印工资方法输入工资

5、设计父类-员工类。子类:工人(Worker),农民(Peasant),教师(Teacher),科学家(Scientist),服务生(Waiter)
1其中工人,农民,服务生只有基本工资
2教师除基本工资外,还有课酬(元/天)
3科学家除基本工资外,还有年终奖
4编写一个测试类,将各种类型的员工的全年工资打印出来

6、假定Grand、Father和Son在同一个包,问:父类和子类中通过this和super都可以调用哪些属性和方法,
class Grand{
String name="AA";
private int age=10;
public void g1(){}
}
class Father extends Grand{
String id= "01";
private double score;
public void f1(){
//super可以访问哪些成员(属性和方法) name,g1()
//this可以访问哪些成员 id,score,f1(),name,g1()
}
}
class Son extends Father{
String name="BB";
public void g1(){}
private void show(){
//super可以访问哪些成员(属性和方法)id,f1(),name,g1
//this可以访问哪些成员name g1() show(),id,f1(),name,g1
}
}
7、写出程序结果
class Test{
String name="Rose";
Test(){System.out.println("Test")}
Test(String name){this.name = name;}
}
class Demo extends Test{
String name="jack";
Demo(){super(); System.out.println("Demo")}
Demo(String s){super(s);}
public void test(){
System.out.println(super.name);
System.out.println(this.name);
}
public static void main(String[] args){
new Demo().test();
//Test,Demo,Rose,jack
new Demo("john").test();
//john,jack
}
}

8、扩展BankAccount类
class BankAccount{
private int balance;//余额
public BankAccount(int initialBalance){
this.balance = initialBalance;
}
//存款
public void deposit(double amount){balance += amount;}
//取款
public void withdraw(double amount){balance -= amount;}
//set和get方法
}
1在上面类的基础上扩展新类CheckingAccount对每次存款和取款都收取1美元的手续费
2SavingsAccount类每个月都有利息产生(earnMonthlyInterest方法被调用),并且有每月三次免手续费的存款或取款。在earnMonthlylnterest方法中重置交易次数
3体会重写的好处

9、设计一个point类,其x和y坐标可以通过构造器提供。提供一个子类LabeledPoint,其构造起接受一个标签值和x,y坐标。如new Labeledpoint("BlackThursday",1929,230.07)

10、编写Doctor类{name,age,job,gender,sal}
相应的getter()和setter()方法,5个参数的构造器,重写父类的equals()方法:
public boolean equals(Object obj),并判断测试类中创建的两个对象是否相等。相等就是判断属性是否相同
11、现有Person类,里面有方法run、eat,Student类继承了Person类,并重写了run方法,自定义了study方法,试写出对象向上转型和向下转型的代码,并写出各自都可以调用哪些方法,并写出方法输出什么
class Person{//父类
public void run(){System.out.println("person run");}
public void eat(){System.out.println("person eat");}
}
class Student extends Person{//子类
public void run(){System.out.println("student run");}
public void study(){System.out.println("student study");}
}
//向上转型:父类的引用指向子类对象
//写代码时编译器看编译类型,运行时才看运行类型
Person p = new Student();
p.run();//输出student run
p.eat();//输出person eat
//向下转型:父类的引用指向子类对象
Person p = (Student)p;
s.run();//student run
s.study();//student study
s.eat();//person eat
12、说出==和equals的区别
名称 概念 用于基本数据类型 用于引用类型
== 比较运算符 可以,判断值是否相等 可以,判断两个对象是否相等
equals Object类的方法 不可以 可以,默认是判断两个对象是否相等
13、案例题目描述:
1做一个Student类,Student类有名称(name),性别(sex),年龄(age),学号(stu_id),做合理封装,通过构造器在创建对象时将4个属性赋值
2写一个Teacher类,Teacher类有名称(name),性别(sex),年龄(age),工龄(work_age),做合理封装,通过构造器在创建对象时将4个属性赋值
3抽取一个父类Person类,将共同属性和方法放到Person类
4学生需要有学习的方法(study),在方法里写"我承诺,我会好好学习"
5教师需要有教学的方法(teach),在方法里写"我承诺,我会认真教学";
6学生和教师都要玩的方法(play),学生玩的是足球,老师玩的是象棋,此方法是返回字符串的,分别返回"xx爱玩足球"和"xx爱玩象棋"。因为玩的方法名称都一样,所以要求此方法定义在父类中,子类实现重写
7定义多态数组,里面保存两个学生和两个教室,要求按照年龄从高到低排序
8定义方法,形参为Person类型,功能:调用学生的study或教师的teach方法

14、程序阅读题在main方法中执行:C c=new C();输出什么
class A{
public A(){System.out.println("我是A类");}
}
class B extends A{
public B(){System.out.println("我是B类的无参");}
public B(String name){
System.out.println(name+"我是B类的有参");
}
}
class C extends B{
public C(){this("hello");System.out.println("我是C类的无参");}
pubilc C(String name){
super("hahah");
System.out.println("我是C类的有参");
}
}
//输出A类,haB类有参,helloC类有参,C类无参
15、什么是多态,多态具体有哪些
多态:方法或对象具有多种形态,是OOP的第三大特征,是建立在封装和继承基础之上
多态具体体现:
1方法多态:(1)重载体现多态(2)重写体现多态
2对象多态:
(1)对象的编译类型和运行类型可以不一致,变异类型在定义时就确定了不能发生变化
(2)对象的运行类型是可以变化的,可以通过getClass()来查看运行类型
(3)编译类型看定义时=号左边,运行类型看=号右边。

16、java的动态绑定机制是什么
1调用对象的方法时,该方法会和对象的内存地址/运行类型绑定
2当调用对象的属性时,没有动态绑定机制,哪里声明,哪里使用

posted @ 2022-02-23 20:53  栗子一块两块  阅读(18)  评论(0)    收藏  举报