面向对象进阶

面向对象进阶

一、递归

1.概念:方法自己调用自己,但是会在某一个时机进行第次返回。

注意:递归的行为,通常要放在递归的条件之后

public class Test {
	public void fun(int i){
		i --;
		if(i>=0){
			fun(i);
		}
	}
}

二、构造方法

1.什么是构造方法

用于初始化一个对象的方法

2.特点

  1. 构造方法名就是类名
  2. 没有返回值
  3. 创建对象时调用

案例:

package com.mine.demo01;

public class Person {
    public Person(){
        System.out.println("DFshmily.STUDIO");
    }
}

package com.mine.demo01;

public class Main {
    public static void main(String[] args) {
        Person person = new Person();
        new Person();
        new Person();
        new Person();
        new Person();
        new Person();
    }
}

结果:
DFshmily.STUDIO
DFshmily.STUDIO
DFshmily.STUDIO
DFshmily.STUDIO
DFshmily.STUDIO
DFshmily.STUDIO

结论

每调用一次构造方法,就会创建一个新的对象

注意:

如果在一个类当中,没有显式的创建构造方法,则会由编译器提供一个无参构造。

3.构造方法的参数

构造方法同样可以有参数,构造方法的形参和实参与普通方法的别无二致

案例:

public class Person {
	public Person(String name){
		System.out.println(String.format("我%s出生了,哈哈哈哈~!!!",name));
	}
}
public class Main {
	public static void main(String[] args) {
		Person person = new Person("DF");
	}
}

结果:
我DF出生了,哈哈哈哈~!!!

三、方法重载

概念:一个类当中,重复载入多个同名方法

1.方法重载的要素:

  1. 方法名要一致
  2. 参数要不一致:参数的数量、类型、位置
  3. 和返回值没有关系
  4. 对构造方法和普通方法都有效

案例:

package com.mine.demo02;

public class Food {
    /**
     * 构造方法与重载
     */
    public Food(){
        System.out.println("0参构造");
    }

    public Food(int f){
        System.out.println("1参构造");
    }

    public Food(int i,double f){
        System.out.println("2参构造");
    }

    public Food(double i,int f){
        System.out.println("2参构造");
    }

    /**
     * 方法的重载
     */

    public void eat(){
        System.out.println("0参方法");
    }
    public void eat(int i){
        System.out.println("1参方法");
    }
    public void eat(int n,double i){
        System.out.println("2参方法");
    }
    public void eat(double a,int i){
        System.out.println("2参方法");
    }

}

2.重载方法的调用

根据参数来进行调用

案例1:构造方法重载调用

package com.mine.demo02;

public class Main {
    public static void main(String[] args) {
        /**
         * 构造方法的调用
         */
        Food food = new Food();
        Food food1 = new Food(1);
        Food food2 = new Food(1,3.14);
        Food food3 = new Food(3.14,1);
    }
}

结果:
0参构造
1参构造
2参构造
2参构造

案例2:普通方法重载调用

package com.mine.demo02;

public class Main {
    public static void main(String[] args) {
         /**
         * 方法的调用
         */
        food.eat();
        food.eat(1);
        food.eat(1,3.14);
        food.eat(3.14,1);
    }
}

结果:
0参的方法
1参的方法
2参的方法
2参的方法

四、this关键字

1.概念:特指对象本身

案例:

package com.mine.demo01;

public class Person {
    public void print(){
        System.out.println(String.format("Person的this打印结果:%s",this));
    }
}
package com.mine.demo01;

public class Main {
    public static void main(String[] args) {
         Person p = new Person();
        p.print();
        System.out.println(String.format("Person的对象p打印结果:%s",p));
    }
}

结果:
Person的this打印结果:com.mine.demo01.Person@5cad8086
Person的对象p打印结果:com.mine.demo01.Person@5cad8086
2.使用案例:

语法:

  • this.属性名
  • this.方法名()
  • this()
package com.mine.demo03;

public class Person {
    
    private int id;//这个访问修饰符是为了保证该属性无法被类以外直接调用
    private String name;
    private int age;
    public Person(){

    }


    public Person(int id){
        this.id = id;
    }
    public Person(int id,String name){
        this(id);
        this.name =name;

    }
    public Person(int id,String name,int age){
        this(id,name);
        this.age = age;
    }

}

3.注意的细节
  1. this调用构造,必须在构造当中
  2. this调用构造,必须在构造的第一行,且只能有一行
  3. 在静态当中无法使用this

五、包

1.概念:
  1. 包的本质是目录的划分
  2. 划分目录的目的是为了防止类与类之间的命名冲突
  3. 包的命名格式:
    • 必须使用小写字母
    • 必须是域名倒置+模块名
    • ”.“不可用与开始和结束,因为”.“在包的命名当中是用于划分目录层级的
  4. 使用规则
    • 一个类如果引用另一个类,被引用的类会存在两种情况:在同一个包中,不在同一个包
      • 在同一个包下的类的引用,不需要引入包的概念(直接用就可以)
      • 不在同一个包下,需要引用该类的时候,需要首先引入该类,或者是其所在包下所有的类
2.案例1:引入一个具体的类
package com.mine.demo07.cl2;//注意其所在包的位置
public class Person {
}
package com.mine.demo07.cl1;
import com.mine.demo07.cl2.Person;//引入了一个对应的具体的类

public class Main {
	public static void main(String[] args) {
		Person p = new Person();
	}
}
3.案例2:引入一个包
package com.mine.demo07.cl1;

import com.mine.demo07.cl2.*;

public class Main {
	public static void main(String[] args) {
		Person p = new Person();
		Dog d = new Dog();
	}
}

注意:批量引入,只针对当前包当中类,不包含子包中的类

4.案例3:引入不同包下的同名类
package com.mine.demo07.cl1;

import com.mine.demo07.cl2.Dog;

public class Main {
	public static void main(String[] args) {
		Dog d = new Dog();
		//使用全局限定名
        com.mine.demo07.cl2.ccl.Dog d2 = new com.mine.demo07.cl2.ccl.Dog();
    }
}

其他规则

  • 每一个类当中都会有一个package,用于标明该类的位置,其有且只能有一行,并必须位于类的第一行
  • 在java中有一个包是不需要显式引入的:java.lang
  • import必须在package和类的申明之间
  • import不能引入两个同名类,否则报错
  • 包是辅助限权控制的重要介质

六、封装

1.getter/setter

对实体类的属性进行封装,其是封装的一种代表形式

步骤:

  1. 将所有属性的访问修饰符改为私有
  2. 通过setter方法给属性赋值
    • 语法格式:
      • 方法名set开头
      • 属性名首字母大写,其他不变,拼接在set之后
      • 参数和要赋值的属性一致
      • 可以没有返回值
  3. 通过getter方法从属性取值
    • 语法格式
      • 方法名get开头
      • 属性名首字母大写,其他不变,拼接在get之后
      • 参数不能有
      • 返回值类型和属性类型保持一致

案例:

package com.mine.demo04;

public class Person {
    //属性私有
    private int id;
    private String name;
    private int sex;
    private int age;

    public void setId(int id){
        this.id = id;
    }
    public int getId(){
        return id;
    }

    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return name;
    }

    public void setSex(int sex){
        this.sex = sex;
    }
    public int getSex(){
        return sex;
    }
    public void setAge(int age){
        this.age = age;
    }
    public int getAge(){
        return age;
    }

}
package com.mine.demo04;

public class Main {
    public static void main(String[] args) {
        Person p = new Person();
        p.setId(1);
        p.setName("df");
        p.setSex(1);
        p.setAge(18);

        System.out.println(String.format("id:%s\tname:%s\tsex:%s\tage:%s",
                p.getId(),p.getName(),p.getSex(),p.getAge()));
    }
}

结果:
id:1	name:df	sex:1	age:18

2.封装的优化

package com.mine.demo04;

public class Person {
    //属性私有
    private int id;
    private String name;
    private int sex = -1;
    private int age = -1;

    public Person(){

    }

    public Person(int id,String name,int sex,int age){
        this.setId(id);
        this.setName(name);
        this.setSex(sex);
        this.setAge(age);
    }

    public void setId(int id){
        if(id<0){
            System.out.println("id取值范围错误!");
        }
        this.id = id;
    }
    public int getId(){
        return id;
    }

    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return name;
    }

    public void setSex(int sex){
        if(sex !=0&&sex !=1){
            System.out.println("性别范围错误!");
            return;
        }
        this.sex = sex;
    }
    public int getSex(){
        return sex;
    }
    public void setAge(int age){
        if(age > 120||age<0){
            System.out.println("年龄范围取值错误!");
            return;
        }
        this.age = age;
    }
    public int getAge(){
        return age;
    }

}

package com.mine.demo04;

public class Main {
    public static void main(String[] args) {
        Person p = new Person();
        p.setId(1);
        p.setName("df");
        p.setSex(3);
        p.setAge(180);

        System.out.println(String.format("id:%s\tname:%s\tsex:%s\tage:%s",
                p.getId(),p.getName(),p.getSex(),p.getAge()));
    }
}

结果:
性别范围错误!
年龄范围取值错误!
id:1	name:df	sex:-1	age:-1

3.链式调用

package com.mine.demo05;

public class Person {
    //属性私有
    private int id;
    private String name;
    private int sex = -1;
    private int age = -1;

    public Person(){

    }

    public Person(int id, String name, int sex, int age){
        this.setId(id);
        this.setName(name);
        this.setSex(sex);
        this.setAge(age);
    }

    public Person setId(int id){
        this.id = id;
        return this;
    }
    public int getId(){
        return id;
    }

    public Person setName(String name){
        this.name = name;
        return this;
    }
    public String getName(){
        return name;
    }

    public Person setSex(int sex){
        this.sex = sex;
        return this;
    }
    public int getSex(){
        return sex;
    }
    public Person setAge(int age){
        this.age = age;
        return this;
    }
    public int getAge(){
        return age;
    }

}

package com.mine.demo05;

public class Main {
    public static void main(String[] args) {
        test(new Person().setId(1)
                            .setName("df")
                                .setSex(1)
                                    .setAge(18));
    }
    public static void test(Person p){
        System.out.println(String.format("id:%s\tname:%s\tsex:%s\tage:%s",
                p.getId(),p.getName(),p.getSex(),p.getAge()));
    }
}

结果:
id:1	name:df	sex:1	age:18

七、继承

1.概念

  • 现实生活中的继承:是赠予和获取的关系,是一方将说要的一切交给另一方
  • 程序中的继承要满足一个前提:is a
  • 父类是具有共性的,子类是具有特性的
  • java是单根继承(即一个子类,只能有一个直接父类)

2.语法

public class ClassName extends ClassName{
    //类的主体
}

好处:

在子类当中,可以获取父类里,那些可以被继承的属性和方法

package com.mine.demo01;

public class Animal {
    public void breathe(){
        System.out.println("动物在呼吸");
    }
}

package com.mine.demo01;

public class Pet extends Animal{
    protected String name;
    protected int age;
    protected int sex;

    public void sleep(){
        System.out.println("宠物在睡觉");
    }
}

package com.mine.demo01;

public class Dog extends Pet{

}

package com.mine.demo01;

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.sleep();
        dog.breathe();
    }
}

3.继承当中的构造方法

注意:

  1. 子类构造必然要调用一个父类构造
  2. 默认调用的是父类的无参构造
  3. 如果没有无参构造,可以使用关键字super
  4. 在子类当中可以使用this调用其他构造,但是最后一定要有super调用父类构造
  • super的使用和this基本一致

    • this调用的是当前对象
    • super调用的是父类对象
    package com.mine.demo02;
    
    public class Father {
        protected int age;
        protected String name;
        public Father(String name){
            this.name = name;
        }
    
        public Father(String name,int age){
            this(name);
            this.age = age;
        }
    }
    
    
    package com.mine.demo02;
    
    public class Child extends Father{
        public Child(String name){
            super(name);
        }
        public Child(String name,int age){
            this(name);
            super.age = age;
        }
    }
    
    

4.无法继承的元素

  • 构造方法无法被继承
  • 私有成员:子类对父类的私有成员不可见
  • 默认修饰符,在不同包的情况下,同样不可见

5.方法的重写(覆盖)

  • 方法重写的前提:
    • 方法名相同
    • 参数相同
    • 返回值相同,或者子类的返回值类型是父类返回值类型的子类型(返回值类型大的永远在父类那)

注意:一般在工作当中,继承的重写,就是子类当中写个一模一样的就行

package com.mine.demo03;
public class Father {
	public void zhaChouDouFu(){
		System.out.println("原味臭豆腐");
	}
}
package com.mine.demo03;
public class Son extends Father {
	@Override
	public void zhaChouDouFu() {
		System.out.println("香草味臭豆腐");
	}
}
package com.mine.demo03;
public class Main {
	public static void main(String[] args) {
		Son son = new Son();
		son.zhaChouDouFu();
	}
}

结果:
香草味臭豆腐

注解:@Override

用来检查当前方法是否是重写的方法

6.一个常见的面试题

重写和重载的区别?

八、多态

同一个事物,在不同的情况下,表现出来的状态不一致

语法:父类申明指向子类对象

package com.mine.demo04;

public class Pet {
    public void eat(){
        System.out.println("宠物在吃东西");
    }
}

package com.mine.demo04;

public class Dog extends Pet{
    public void eat(){
        System.out.println("骨头");
    }
}

package com.mine.demo04;

public class Cat extends Pet{
    public void eat(){
        System.out.println("小鱼干");
    }
}

package com.mine.demo04;

public class Main {
    public static void main(String[] args) {
        //父类申明指向子类对象
        Pet dog = new Dog();
        dog.eat();
        Pet cat = new Cat();
        cat.eat();
    }
}

结果:
骨头
小鱼干

注意:

  1. 父类和子类之间,必须存在继承关系,但不一定是直接继承关系。即父类可以是爸爸,也可以是爷爷......
  2. 父类引用只可以调用父类的属性和方法,不可以调用子类的属性和方法。父类是一个标准!

1.装箱

​ 父类申明指向子类对象

2.拆箱

​ 把父类型向子类型转换

package com.mine.demo04;

public class Pet {
    public void eat(){
        System.out.println("宠物在吃东西");
    }
}

package com.mine.demo04;

public class Dog extends Pet{
    public void eat(){
        System.out.println("骨头");
    }

    public void callWa(){
        System.out.println("汪汪汪~");
    }
}

package com.mine.demo04;

public class Cat extends Pet{
    public void eat(){
        System.out.println("小鱼干");
    }

    public void callMiao(){
        System.out.println("喵喵喵~");
    }
}

package com.mine.demo04;

public class Main {
    public static void main(String[] args) {
        //父类申明指向子类对象
        Pet dog = new Dog();
        dog.eat();
        Pet cat = new Cat();
        cat.eat();


        //拆箱
        Dog dog1 = (Dog) dog;
        Cat cat1 = (Cat) cat;
        //调用子类的属性和方法
        dog1.callWa();
        cat1.callMiao();
    }
}


结果:
骨头
小鱼干
汪汪汪~
喵喵喵~

3.关键字:instanceof

用于判断某个对象是否是某个类型

案例:

import com.mine.demo01.Cat;
import com.mine.demo01.Dog;
import com.mine.demo01.Pet;
public class Main {
	public static void main(String[] args) {
		Pet d = new Dog();
		Pet c = new Cat();
		Pet p = new Pet();
		//匹配类型
		System.out.println(d instanceof Dog);
		System.out.println(d instanceof Pet);
		System.out.println(d instanceof Cat);
		System.out.println(p instanceof Pet);
		System.out.println(p instanceof Dog);
		System.out.println(p instanceof Cat);
	}
}

结果:
true
true
false
true
false
false

结论:判断类型是否匹配,主要观察的是实现类(实例)

4.优化拆箱

package com.mine.demo04;

public class Main {
    public static void main(String[] args) {
        //父类申明指向子类对象
        Pet dog = new Dog();
        dog.eat();
        Pet cat = new Cat();
        cat.eat();
        Pet p = new Pet();


        //拆箱
        if(dog instanceof Dog){
            Dog dog1 = (Dog) dog;
            dog1.callWa();
        }
        if(cat instanceof Cat){
            Cat cat1 = (Cat) cat;
            cat1.callMiao();
        }
        //调用子类的属性和方法
    }
}

九、Object类

所有类的超类,在整个Java体系中,都要直接或者间接的继承Object类

当一个类没有显式的继承某个类时,其将默认继承Object类

1.获取地址:hashCode

package com.mine.demo04;
public class Main {
	public static void main(String[] args) {
		Person p = new Person();
		System.out.println(p.hashCode());
	}
}

结果:
1163157884

2.打印对象:toString

Object的toString方法

如果要打印对象,会默认调用该方法。打印内容,为该方法返回的字符串

public String toString() {
	return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

重写

@Override
public String toString() {
	return "Person{" +
			"id=" + id +
			", name='" + name + '\'' +
			", age=" + age +
			", sex=" + sex +
			'}';
}

一个有价值的数据格式:json

  1. 对象:
  2. 集合或者数组:[{},{},{}]
[{"id":1,"name":"ybb","dogs":[{"name":"cp"},{"name":"bd"}]},
{"id":2,"name":"lzl","dogs":[{"name":"jp"},{"name":"xb"}]}]

3.比较两个对象是否相等,重写equals

package com.mine.demo05;

public class Person {
    private int id;
    private String name;

    public void setId(int id){
        this.id = id;
    }
    public int getId(){
        return id;
    }

    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return name;
    }

    public boolean equals(Object obj){
        //1.比地址
        if(this == obj){
            return true;
        }

        //2.转类型
        if(obj instanceof Person){
            /*
            //拿this p1和这个p2对象的属性值进行比较,
            如果主观上所有属性值都相同,那么结果为true
            有一个属性不同,结果为false
             */
            Person p1 = this;
            Person p2 = (Person) obj;
            if(p1.id != p2.id){
                return false;
            }
            if(p1.name!=null&&!p1.name.equals(p2.name)){
                return false;
            }
            if(p2.name!=null&&!p2.name.equals(p1.name)){
                return false;
            }
        }else {
            //类型不同,直接不需要比
            return false;
        }
        return true;
    }
}

结论:提供一个在何种情况下才算是相等的规则,其属于一种约定。

作业2:

添加一个新的功能
删除学生信息
1.检查是否存在
2.删除后要排序

十、访问修饰符

  • public(常用)
  • private(常用)
  • 默认
  • protected

1.public:(共有的)

任何地方都可以访问

2.private:(私有的)

只能在本类当中

image

3.默认的

  • 当前类当中

  • 同一个包内可以访问

4.protected:受保护的

  • 当前类当中
  • 同一个包内可以访问
  • 如果不在同一个包当中,想要访问有一个例外,即在其子类当中

案例:

package com.mine.demo03;
public class Test {
	public int i;
	protected int j;
	int k;
	private int h;
}
package com.mine.demo03.cl;

import com.mine.demo03.Test;

public class Test2 extends Test {
	public void fun(){
		super.j = 100;
	}
}

十一、类图

image

注意:

+代表public

-代表private

变量名:变量类型

方法名(参数名:参数类型......):返回值类型

作业:

改造学员成绩管理系统:

  1. 将所有的类当中,属性全部隐藏,提供getter/setter方法,及其构造方法
  2. 增加一个功能,修改学生成绩
    • 输入学生学号后,需要检查该学号是否存在
    • 修改学生成绩后,重新排序
posted @ 2023-03-14 17:44  DFshmily  阅读(21)  评论(0编辑  收藏  举报