JAVA 面对对象进阶-上(八)

面对对象进阶-上(八)

staic

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

静态变量

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

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

调用方式

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

:

//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);
    }
}
//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。
定义一个工具类,获取集合中最大学生的年龄

//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;
    }
}
//工具类
//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;
    }
}
//测试类
//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

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

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

范例
//父类
public class Father{
    String name="Father";
}
//子类
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
    }
}
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. 建议:重写的方法尽量和父类一致
  6. 只有被添加到虚方法表中的方法才能被重写
范例

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

//父类
public class Dog {
    public void eat(){
        System.out.println("吃狗粮");
    }
    public void drink(){
        System.out.println("喝水");
    }
    public void lookHome(){
        System.out.println("看家");
    }
}

//子类
//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("吃骨头");
    }
}
//测试类
//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调用
  • 除了Object类,所有构造方法第一行,都有个隐藏的super()
  • 默认先访问父类中无参的构造方法,再执行自己
  • 若想访问父类有参构造,需手动书写

this和super

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

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

:this()和super()都在争夺构造方法第一行的位置,所以二者不可共存。
super省略规则:被调用的变量和方法,在子类中不存在,super.可以直接省略

范例

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

  1. 经理
    • 成员变量:工号,姓名,工资,管理奖金
    • 成员方法:工作(管理其他人),吃饭(吃米饭)
  2. 厨师
    • 成员变量:工号,姓名,工资
    • 成员方法:工作(炒菜),吃饭(吃米饭)
//父类
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("吃米饭");
    }
}
//经理
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("炒菜");
    }
}
//测试类
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

范例

//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.定义狗类
		属性:
			年龄,颜色
		行为:
			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中调用特有方法?
代码
//父类
//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("没有这种动物");
        }
    }
}
//子类
//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("抓老鼠");
    }
}
//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类。
包名书写规则:公司域名反写.包的作用,全部英文小写,见名知意。例如:

//若域名为www.ljsblog.com,包名为:com.ljsblog.domain1
package com.ljsblog.domain1

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

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

判断是否需要导包

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

final

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

final修饰成员变量的注意事项:

  1. final修饰成员变量,不允许修饰默认值
  2. final修饰成员变量的初始化时机
    1. 在定义的时候直接赋值
    2. 在构造方法中完成赋值

final变量修饰变量的命名规范:

  1. 若变量名是一个单词,所有字母大写
  2. 若变量名是多个单词,所有字母大写,中间用下划线分割

权限修饰符

定义:用来控制一个成员(成员变量,方法,构造方法,内部类)能够访问的范围的。
分类;由小到大,private < 缺省/默认(空着不写)< protected < public

修饰符同一类中同一个包中其他类不同包下的子类不同包下的无关类
private不能不能不能
默认不能不能
proteced不能
public

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

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

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

代码块

分类

  • 局部代码块(已淘汰)
  • 构造代码块(已淘汰)
  • 静态代码块(重点)
  • 同步代码块(牵扯多线程)

局部代码块

位置:方法中的一对大括号。
作用:提前结束变量的生命周期(已淘汰)

构造代码块

位置:类中方法外的一对大括号。
作用:可以把多个构造方法中重复的代码抽取出来。
执行时机:创建对象,执行构造方法时执行构造代码块(先于构造方法执行)

静态代码块

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

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;
    }
}
package com.ljsblog.domain1;
public class Test {
    public static void main(String[] args) {
        Student s1=new Student();
        Student s2=new Student(18,"张三");
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值