面对对象进阶-上(八)


面对对象进阶-上(八)

staic

static表示静态,是JAVA中的一个修饰符,可修饰成员方法,成员变量

静态变量

被static修饰的成员变量,叫做静态变量。
特点

  • 被该类所有对象共享
  • 不属于对象,属于类
  • 随着类的加载而加载,优先于对象存在

调用方式

  • 类名调用(推荐)
  • 对象名调用

:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//Student.class
public class Student{
private String name;
private int age;
public static String teacherName;
public Student(){}
public Student(String name,int age){
this.name=name;
this.age=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;
}

public void show(){
System.out.println("学生姓名:"+name+" 学生年龄:"+age+" 老师姓名:"+teacherName);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Test.class
public class Test{
public static void main(String[] args){
//类名调用
Student.teacherName="王五";
Student student1=new Student("张三",18);
//也可以对象名调用
//student1.teacherName="王五";
student1.show();
Student student2=new Student();
student2.show();
}
}
/*
学生姓名:张三 学生年龄:18 老师姓名:王五
学生姓名:null 学生年龄:0 老师姓名:王五
*/

静态方法

被static修饰的成员方法,叫做静态方法。
特点

  • 多用在测试类或工具类中
  • Javabean类中很少用

补充:工具类是帮我们做一些事情的,但不描述任何事物的类

  1. 工具类类名需见名知意
  2. 私有化构造方法。
  3. 方法定义为静态

调用方式

  • 类名调用(推荐)
  • 对象名调用

范例

定义一个集合,存储三个学生对象。
学生类属性:name,age。
定义一个工具类,获取集合中最大学生的年龄

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//javabean类
//Student.java
public class Student{
private String name;
private int age;
public Student(){}
public Student(String name,int age){
this.name=name;
this.age=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;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//工具类
//StudentMaxAge.java
import java.util.ArrayList;
public class StudentMaxAge{
private StudentMaxAge(){}
public static int age(ArrayList<Student> list){
int max=list.get(0).getAge();
for(int i=1;i<list.size();i++){
int n=list.get(i).getAge();
if(n>max){
max=n;
}
}
return max;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//测试类
//test.java
import java.util.ArrayList;
public class Test{
public static void main(String[] args){
Student student1=new Student("张三",18);
Student student2=new Student("李四",19);
Student student3=new Student("王五",17);
ArrayList<Student> list=new ArrayList<>();
list.add(student1);
list.add(student2);
list.add(student3);
int max=StudentMaxAge.age(list);
System.out.println(max);//19
}
}

注意事项

  • 静态方法只能访问静态变量和静态方法
  • 非静态方法可以访问静态变量或静态方法,也可以访问非静态的成员变量和非静态的成员方法
  • 静态方法中没有this关键字

继承

定义:继承是面对对象三大特征之一,可以让类与类间产生子父关系。
好处:可以把多个子类重复的代码抽取到父类中,子类可直接使用,减少代码冗余,提高代码的复用性。
格式
public class 子类 extends 父类{}
继承后子类的特点:
子类可得到父类的属性和行为,子类可使用。
子类可在父类的基础上新增其他功能,子类更强大。

特点

  1. JAVA只能单继承:一个类只能继承一个直接父类
  2. JAVA不支持多继承:但支持多层继承
  3. JAVA所有类都直接或间接继承于Object类

子类继承父类的内容

  • 构造方法:无论是否私有,都不能继承
  • 成员变量:无论是否私有,都能继承
    • 注:private成员变量虽然能继承,但不可直接使用
  • 成员方法:若虚方法表存有该方法,则可以继承,否则不能继承
    • 虚方法表存储的方法:非private,非static,非final

继承中成员变量的访问特点

遵循就近原则,先在局部位置找,本类成员位置找,父类成员位置找,逐级往上。

范例

1
2
3
4
//父类
public class Father{
String name="Father";
}
1
2
3
4
5
6
7
8
9
10
//子类
public class Son extends Father{
String name="Son";
public void printName(){
String name="printName";
System.out.println(name);//从局部位置开始寻找,打印结果为printName
System.out.println(this.name);//从本类成员位置开始寻找,打印结果为Son
System.out.println(super.name);//从父类成员位置开始寻找,打印结果为Father
}
}
1
2
3
4
5
6
7
8
9
10
11
public class Test{
public static void main(String[] args){
Son son=new Son();
son.printName();
}
}
/*
printName
Son
Father
*/

方法的重写

当父类方法不能满足子类现在的需求时,需进行方法重写。
@Override重写注解:@override是放在重写后的方法上,校验子类重写时语法是否正确,建议重写方法都加@Override注解。
方法重写的本质:覆盖虚方法表中的方法。
方法重写的注意事项

  1. 重写方法的名称,形参列表需与父类一致
  2. 子类重写父类方法时,访问权限子类必须大于等于父类
  3. 子类重写父类方法时,返回值类型子类必须小于等于父类
  4. 建议:重写的方法尽量和父类一致
  5. 只有被添加到虚方法表中的方法才能被重写

范例

有三种狗:哈士奇,沙皮狗,中华田园犬
不考虑属性,只考虑行为。
请按照继承的思想特点惊醒继承体系的设计。
行为:
哈士奇:吃饭(吃狗粮),喝水,看家,拆家
沙皮狗:吃饭(吃狗粮,吃骨头),喝水,看家
中华田园犬:吃饭(吃剩饭),喝水,看家

1
2
3
4
5
6
7
8
9
10
11
12
13
//父类
public class Dog {
public void eat(){
System.out.println("吃狗粮");
}
public void drink(){
System.out.println("喝水");
}
public void lookHome(){
System.out.println("看家");
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//子类
//ChineseDog.java
public class ChineseDog extends Dog {
@Override
public void eat(){
System.out.println("吃剩饭");
}
}

//Husky.java
public class Husky extends Dog {
public void DestroyHome(){
System.out.println("拆家");
}
}

//Sharpei.java
public class Sharpei extends Dog{
@Override
public void eat(){
super.eat();
System.out.println("吃骨头");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//测试类
//Test.java
public class Test{
public static void main(String[] args){
Husky husky=new Husky();
husky.eat();
husky.drink();
husky.lookHome();
husky.DestroyHome();
System.out.println("=================");
Sharpei sharpei=new Sharpei();
sharpei.eat();
sharpei.drink();
sharpei.lookHome();
System.out.println("=================");
ChineseDog chineseDog=new ChineseDog();
chineseDog.eat();
chineseDog.drink();
chineseDog.lookHome();
}
}
/*
吃狗粮
喝水
看家
拆家
=================
吃狗粮
吃骨头
喝水
看家
=================
吃剩饭
喝水
看家
*/

继承中构造方法的访问特点

  • 子类不能继承父类的构造方法,但可通过super调用
  • 子类构造方法第一行,有个默认的super()
  • 默认先访问父类中无参的构造方法,再执行自己
  • 若想访问父类有参构造,需手动书写

this和super

this:理解为一个变量,表当前方法调用者地址值。
super:代表父类存储空间。
对比:

  1. 访问成员变量
    • this.成员变量,访问本类成员变量
    • super.成员变量,访问父类成员变量
  2. 访问成员方法
    • this.成员方法(…),访问本类成员方法
    • super.成员方法(…),访问父类成员方法
  3. 访问构造方法
    • this(…),访问本类其它构造方法
    • super(…),访问父类构造方法

范例

带有继承结构的标准Javabean类。

  1. 经理
    • 成员变量:工号,姓名,工资,管理奖金
    • 成员方法:工作(管理其他人),吃饭(吃米饭)
  2. 厨师
    • 成员变量:工号,姓名,工资
    • 成员方法:工作(炒菜),吃饭(吃米饭)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//父类
public class Employee{
private String id;
private String name;
private int salary;
public Employee(){}
public Employee(String id,String name,int salary){
this.id=id;
this.name=name;
this.salary=salary;
}
public void setId(String id){
this.id=id;
}
public String getId(){
return id;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setSalary(int salary){
this.salary=salary;
}
public int getSalary(){
return salary;
}
public void work(){
System.out.println("工作");
}
public void eat(){
System.out.println("吃米饭");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//经理
public class Manager extends Employee{
private double manageSalary;
public Manager(){}
public Manager(String id,String name,int salary,double manageSalary){
super(id,name,salary);
this.manageSalary=manageSalary;
}
public void setManageSalary(double manageSalary){
this.manageSalary=manageSalary;
}
public double getManageSalary(){
return manageSalary;
}
@Override
public void work(){
System.out.println("管理其他人");
}
}

//厨师
public class Cooker extends Employee{
public Cooker(){}
public Cooker(String id,String name,int salary){
super(id,name,salary);
}
@Override
public void work(){
System.out.println("炒菜");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//测试类
public class Test{
public static void main(String[] args){
Manager manager=new Manager("manager001","张三",3000,1500.33);
System.out.println("经理工号:"+manager.getId()+" 姓名:"+manager.getName()+
" 工资:"+manager.getSalary()+" 管理奖金:"+manager.getManageSalary());
manager.work();
manager.eat();
System.out.println("======================");
Cooker cooker=new Cooker();
cooker.setId("cooker001");
cooker.setName("李四");
cooker.setSalary(2500);
System.out.println("厨师工号:"+cooker.getId()+" 姓名:"+cooker.getName()+" 工资:"+manager.getSalary());
cooker.work();
cooker.eat();
}
}
/*
经理工号:manager001 姓名:张三 工资:3000 管理奖金:1500.33
管理其他人
吃米饭
======================
厨师工号:cooker001 姓名:李四 工资:3000
炒菜
吃米饭
*/

多态

定义:同类型的对象,表现出的不同形态。
表现形式
父类类型 对象名称=子类对象;
前提

  • 有继承关系
  • 有父类引用指向子类对象
  • 有方法重写

好处:使用父类型作为参数,可以接受所有子类对象,体现多态的扩展性和便利。

特点

  • 调用成员变量:编译看左边,运行也看左边
    • 编译看左边:javac编译代码时,会看左边的父类是否有这个变量,若有,编译成功,若无,编译失败
    • 运行也看左边:java运行代码时,实际获取的就是左边父类中成员变量的值
    • 在子类对象中,会把父类的成员变量也继承下来。
  • 调用成员方法:编译看左边,运行也看右边
    • 编译看左边,javac编译代码时,会看左边的父类是否有这个方法,若有,编译成功,若无,编译失败
    • 运行看右边:java运行代码时,实际运行的是子类中的方法。
    • 若子类对方法进行重写,则虚方法表中是会把父类的方法进行覆盖的。

优势与劣势

优势

多态形式下,右边对象可实现解耦合,便于扩展和维护。
定义方法时,使父类型作为参数,可接收所有子类对象,体现多态的扩展性和便利。

劣势

不能调用子类的特有功能,当调用方法时,编译看左边,运行看右边,编译时会先检查左边的父类是否有这个方法,若无则直接报错。
解决方法

  • 可以转换成真正的子类类型,从而调用子类独有功能,转换方式有:
    • 自动类型转换,例如:Person p=new Student();
    • 强制类型转换:例如:Student s=(Student)p;
  • 转换类型与真实对象不一致会报错
  • 转换时用instanceof关键字进行判断
    • 语法:boolean result=object instanceof class
    • 说明:若object是class一个实例,则返回true,若不是或者object是null,则返回false

范例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//Test.class
public class Test{
public static void main(String[] args){
Person p=new Student();
if(p instanceof Teacher){
Teacher t=(Teacher)p;
t.work();
}else if(p instanceof Student){
Student s=(Student)p;
s.work();
}else{
System.out.println("没有这个类型");
}
}
}

//父类
//Person.class
public class Person{
public void eat(){
System.out.println("吃饭");
}
}
//子类
//Teacher.class
public class Teacher extends Person{
public void work(){
System.out.println("教学");
}
}
//Student.class
public class Student extends Person{
public void work(){
System.out.println("听课");
}
}

范例

需求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
根据需求完成代码:
1.定义狗类
属性:
年龄,颜色
行为:
eat(String something)(something表示吃的东西)
看家lookHome方法(无参数)

2.定义猫类
属性:
年龄,颜色
行为:
eat(String something)方法(something表示吃的东西)
逮老鼠catchMouse方法(无参数)

3.定义Person类//饲养员
属性:
姓名,年龄
行为:
keepPet(Dog dog,String something)方法
功能:喂养宠物狗,something表示喂养的东西
行为:
keepPet(Cat cat,String something)方法
功能:喂养宠物猫,something表示喂养的东西
生成空参有参构造,set和get方法
4.定义测试类(完成以下打印效果):
keepPet(Dog dog,String somethind)方法打印内容如下:
年龄为30岁的老王养了一只黑颜色的2岁的狗
2岁的黑颜色的狗两只前腿死死的抱住骨头猛吃
keepPet(Cat cat,String somethind)方法打印内容如下:
年龄为25岁的老李养了一只灰颜色的3岁的猫
3岁的灰颜色的猫眯着眼睛侧着头吃鱼
5.思考:
1.Dog和Cat都是Animal的子类,以上案例中针对不同的动物,定义了不同的keepPet方法,过于繁琐,能否简化,并体会简化后的好处?
2.Dog和Cat虽然都是Animal的子类,但是都有其特有方法,能否想办法在keepPet中调用特有方法?
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//父类
//Animal.class
public class Animal{
private int age;
private String color;
public Animal(){};
public Animal(int age,String color){
this.age=age;
this.color=color;
}
public void setAge(int age){
this.age=age;
}
public int getAge(){
return age;
}
public void setColor(String color){
this.color=color;
}
public String getColor(){
return color;
}
public void eat(String something){
System.out.println("吃"+something);
}
}

//Person.class
public class Person{
private String name;
private int age;
public Person(){}
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 void keepPet(Animal animal, String something){
if(animal instanceof Dog){
Dog d=(Dog)animal;
System.out.println("年龄为"+age+"的"+name+"养了一只"+d.getColor()+"颜色的"+d.getAge()+"的狗");
d.eat(something);
d.lookHome();
}else if(animal instanceof Cat){
Cat c=(Cat)animal;
System.out.println("年龄为"+age+"的"+name+"养了一只"+c.getColor()+"颜色的"+c.getAge()+"的猫");
c.eat(something);
c.catchMouse();
}else{
System.out.println("没有这种动物");
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//子类
//Dog.class
public class Dog extends Animal{
public Dog(){}
public Dog(int age,String color){
super(age,color);
}
@Override
public void eat(String something){
System.out.println(getAge()+"岁的"+getColor()+"颜色的狗两只前腿死死的抱住"+something+"猛吃");
}
public void lookHome(){
System.out.println("看家");
}
}

//Cat.class
public class Cat extends Animal{
public Cat(){}
public Cat(int age,String color){
super(age,color);
}
@Override
public void eat(String something){
System.out.println(getAge()+"岁的"+getColor()+"颜色的猫眯着眼睛侧着头吃"+something);
}
public void catchMouse(){
System.out.println("抓老鼠");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Test.class
public class Test{
public static void main(String[] args){
Person p1=new Person("老王",30);
Dog d=new Dog(2,"黑");
p1.keepPet(d,"屎");

Person p2=new Person("老李",25);
Cat c=new Cat(3,"灰");
p2.keepPet(c,"老鼠");

}
}
/*
年龄为30的老王养了一只黑颜色的2的狗
2岁的黑颜色的狗两只前腿死死的抱住屎猛吃
看家
年龄为25的老李养了一只灰颜色的3的猫
3岁的灰颜色的猫眯着眼睛侧着头吃老鼠
抓老鼠
*/

作用:包就是文件夹,用来管理各种不同功能的Java类。
包名书写规则:公司域名反写.包的作用,全部英文小写,见名知意。例如:

1
2
//本网站域名为www.ljsblog.com,包名为:com.ljsblog.domain1
package com.ljsblog.domain1

全类名:包名.类名。例如:

1
一个Student类位于com.ljsblog.domain下,则其全类名,com.ljsblog.domain.Student 

判断是否需要导包

  • 使用同一包的类时,不需导包
  • 使用java.lang包的类时,不需导包
  • 其他情况都需导包
  • 若同时使用两个包的同名类,需用全类名。

final

  • final修饰方法:最终方法,不能被重写
  • final修饰的类:最终类,不能被继承
  • final修饰的变量:是常量,不能被修改
    • 基本数据类型:变量的值不能更改
    • 引用数据类型:地址值不能修改,内部属性值可以修改

权限修饰符

定义:用来控制一个成员(成员变量,方法,构造方法,内部类)能够访问的范围的。
分类;由小到大,private < 缺省/默认(空着不写)< protected < public
| 修饰符 | 同一类中 | 同一个包中其他类 | 不同包下的子类 | 不同包下的无关类 |
| ——- | ——- | ————— | ————- | ————— |
| private | 能 | 不能 | 不能 | 不能 |
| 默认 | 能 | 能 | 不能 | 不能 |
| proteced | 能 | 能 | 能 | 不能 |
| public | 能 | 能 | 能 | 能 |

使用规则:实际开发中,一般只用private和public。

  • 成员变量私有
  • 方法公开

特例:若方法中代码是抽取其他方法中共性代码,这个方法一般也私有。

代码块

分类

  • 局部代码块(已淘汰)
  • 构造代码块(已淘汰)
  • 静态代码块(重点)

局部代码块

作用:提前结束变量的生命周期(已淘汰)

构造代码块

写在乘员位置的代码块。
作用:可以把多个构造方法中重复的代码抽取出来。
执行时机:我们在创建本类对象时会先执行构造代码,

静态代码块

格式:static{}
特点:需通过static关键字修饰,随着类的加载而加载,自动触发,只执行一次。
使用场景:在类加载时,做一些数据初始化时使用。
范例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.ljsblog.domain1;
public class Student{
private int age;
private String name;
static{
System.out.println("静态代码区");
}
public Student(){
System.out.println("无参构造");
}
public Student(int age,String name){
System.out.println("有参构造");
this.age=age;
this.name=name;
}
public void setAge(int age){
this.age=age;
}
public int getAge(){
return age;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
}
1
2
3
4
5
6
7
8
package com.ljsblog.domain1;
public class Test {
public static void main(String[] args) {
Student s1=new Student();
Student s2=new Student(18,"张三");
}
}


Author: ljs
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source ljs !
评论
  TOC