【Java笔记】09 面向对象

【Java笔记】09 面向对象

一、类与对象

在这里插入图片描述

  • 属性
    成员属性=属性=field 访问修饰符 属性类型 属性名;
    访问修饰符:public protected 默认 private
    属性不赋值有默认值,跟数组默认值相同
  • 方法(成员方法)
    当程序执行到方法时,开辟一个独立的栈空间;
    执行完毕,或者到return语句时,返回;
    返回到调用方法的语句,继续执行后面的代码
    方法的定义:
    访问修饰符 返回数据类型 方法名(形参列表…){//方法体
    语句;
    return 返回值;
    }

同一个类中的方法调用,直接调用即可,不需要创建对象

class A{
	//同一个类中的方法调用,直接调用即可,不需要创建对象
		pubilc void print(int n){
			System.out.println("输出");
		}
		public void test(){
			print();
		}
}

跨类中的方法调用:A类调用B类方法,需要通过对象名调用。即创建B类的对象,再调用方法

二、方法重载

java中允许同一个类中,多个同名方法的存在,但要求形参列表不一致
方法名:必须相同
形参列表:必须不同(形参类型或个数或顺序,至少有一样不同,参数名无要求)
返回类型:无要求

三、可变参数

java允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法
可变参数的实参可以为0个或任意多个
可变参数的实参可以为数组
可变参数的本质就是数组
可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数在最后
一个形参列表中最多只能出现一个可变参数

public class VarParameter{
	public static void main(String[] args){
		//求2个、3个、4个...参数的和
		HspMethod m = new HspMethod();
		System.out.println(m.sum(1,5,100));
		System.out.println(m.sum(1,19));
	}
}

class HspMethod{
	//int...表示接受的是可变参数,类型是int,即可接收多个int(0-多)
	//使用可变参数时,可以当做数组来使用,即nums可以当做数组
	//遍历nums求和即可
	public int sum(int... nums){
		int res = 0;
		for(int i =0;i < nums.length;i++){
			res += nums[i];
		}
		return res;
	}
}

四、作用域

1.java中,主要的变量就是属性(成员变量)和局部变量
2.局部变量一般是指在成员方法中定义的变量
3.Java作用域分类
   全局变量:即属性,作用域为整个类
   局部变量:除了属性以外的其他变量,作用域为定义它的代码块中
4.属性可以不赋值,直接使用,因为有默认值,局部变量必须赋值后才能使用,没有默认值
5.作用域范围
   全局变量/属性:可以被本类使用,或其他类使用(通过对象调用)
   局部变量:只能在本类中对于的方法中使用
6.全局变量可以加修饰符,局部变量不能加修饰符

五、构造方法/构造器

构造方法又叫构造器,是类的一种特殊的方法,主要作用是完成对新对象的初始化
方法名和类名相同
没有返回值
创建对象时,系统自动的调用该类的构造器完成对象的初始化
[修饰符] 方法名(形参列表){
方法体;
}
1.构造器的修饰符可以默认,也可以时public protected private
2.构造器没有返回值
3.方法名和类名字必须一样
4.参数列表和成员方法规则一样
5.一个类可以定义多个不同的构造器,即构造器重载
6.定义了自己的构造器,默认构造器就覆盖了,除非显式定义一下

public class Constructor{
	public static void main(String[] args){
		//new一个对象时,直接通过构造器初始化
		Person p1 = new Person("jack",3);
	}
}

class Person{
	String name;
	int age;
	public Person(String pName,int pAge){
		name = pName;
		age = pAge;
	}
}

六、this

java虚拟机给每个对象分配this,代表当前对象
this 关键字可以用来访问本类的属性、方法、构造器
this 用于区分当前类的属性和局部变量
访问成员方法的语法:this.方法名(参数列表);

class T{
	public void f1(){
		System.out.println("f1()");
	}

	public void f2(){
		System.out.println("f2()");
		//调用本类的f1
		//第一种方法
		f1();
		//第二种方法
		this.f1();
	}
}

访问构造器语法:this(参数列表); 注意只能在构造器中使用(即只能在构造器中访问另外一个构造器, 必须放在第一 条语句)

class T{
	public T(){
		this("jack",20);//访问构造器语法:this(参数列表);必须放置第一条语句
		System.out.println("T()构造器");
	}
	public T(String name,int age){
		System.out.println("T(String name,int age)构造器");
	}
}

this 不能在类定义的外部使用,只能在类定义的方法中使用

七、访问修饰符

公开 public
受保护 protected 对子类和同一包的类公开
默认 对同一个包的类公开
私有 private 不对外公开
只有默认和public可以修饰类

八、封装

把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作[方法],才能对数据进行操作。
步骤:
1.先对属性私有化,让外部不能直接修改属性
2.提供一个公共的set方法,用于对属性判断并赋值

public void setXxx(类型 参数名){
	//验证
	属性 = 参数名;
}

3.提供一个公共的get方法,用于获取属性的值

public getXxx(){//权限判断
	return xx;
}
  • 有构造器时想使用set方法,在构造器中使用set
public Person(String name, int age, double salary) {
//        this.name = name;
//        this.age = age;
//        this.salary = salary;
        setSalary(salary);
        setAge(age);
        setName(name);
    }

九、继承

多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类(基类,超类),在父类中定义这些相同的属性和方法,子类(派生类)通过extends声明继承父类
子类继承了所有的属性和方法,但私有属性和方法不能在子类直接访问,要通过父类公共的方法;
创建子类时,不管使用子类的哪个构造器,默认都会调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super指定使用父类的哪个构造器,即在子类构造器中写super(对应参数列表);
super()使用时放在构造器的第一行,super只能在构造器中使用;
super()和this()都只能放在第一行->不能同时存在;
java所有类都是Object类的子类,Object是所有类的基类;
父类构造器的调用不限于父类,而是一直往上追溯;
java单继承,子类最多只能直接继承一个父类;
子类和父类之间要满足is-a关系;

public class Encap {
    public static void main(String[] args) {
        Son son = new Son();
        //内存的布局
        // 要按照查找关系来返回信息
        // (1) 首先看子类是否有该属性
        // (2) 如果子类有这个属性,并且可以访问,则返回信息
        // (3) 如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息..)
        // (4) 如果父类没有就按照(3)的规则,继续找上级父类,直到 Object...
        System.out.println(son.name);//返回就是大头儿子
        //System.out.println(son.age);//会报错,age是私有的属性
        System.out.println(son.getAge());//返回的就是 39
        System.out.println(son.hobby);//返回的就是旅游
    }
}

class GrandPa {//爷类
    String name = "大头爷爷";
    String hobby = "旅游";
}

class Father extends GrandPa {//父类
    String name = "大头爸爸";
    private int age = 39;

    public int getAge() {
        return age;
    }
}

class Son extends Father { //子类
    String name = "大头儿子";
}

十、super关键字

访问父类的属性、方法、构造器:
1.访问属性(不能访问父类的private属性)
   super.属性名;
2.访问父类的方法,不能访问父类的private方法
   super.方法名(参数列表);
3.访问父类的构造器
   super(参数列表); 只能放在第一句
子类、父类方法有重名时,为了访问父类的成员,用super。没有重名,super,this,直接访问一样
找方法时,顺序:
1.先找本类,如果有,调用
2.如果没有,则找父类。父类如果有,并可以调用,则调用
3.如果父类没有,继续找父类的父类,知道Object
查找方法过程中,找到了但不能访问(比如private),报错

十一、方法重写/覆盖

子类有一个方法和父类的某个方法的名称、返回类型、参数一样,子类的这个方法覆盖了父类的方法
返回类型父类的返回类型是子类的父类也可以。比如父类返回类型是Object,子类是String
子类方法不能缩小父类方法的访问权限

  • 比较方法重载和重写
名称发生范围方法名形参列表返回类型修饰符
重载本类必须一样类型,个数或顺序至少有一个不同无要求无要求
重写父子类必须一样相同子类重写的方法,返回类型和父类的返回类型一直或者是其子类子类方法不能缩小父类方法的访问范围

多态

问题:代码复用性不高
解决方案:多态–>方法或对象有多种形态

  1. 方法的多态
       方法重载、重写体现多态
  2. 对象的多态
    (1)一个对象的编译类型和运行类型可以不一致
    父类的引用指向子类的对象 Animal an = new Dog(); an的编译类型是Animal,运行类型是Dog
    (2)编译类型在定义对象时就确定了,不能改变
    (3)运行类型时可以变化的
    an = new Cat(); an的运行类型变成了Cat,编译类型仍然是Animal
    (4)编译类型看定义时=的左边,运行类型看=的右边
public class Poly{
	//animal编译类型就是Animal,运行类型Dog
	Animal animal = new Dog();
	animal.cry(); //狗叫

	//animal编译类型就是Animal,运行类型Cat
	animal = new Cat();
	animal.cry(); //猫叫
}

多态的前提时两个对象/类存在继承关系

  • 向上转型
    (1)本质:父类的引用指向了子类的对象
    (2)语法:父类类型 引用名 = new 子类类型();
    (3)可以调用父类中的所有成员(遵循访问权限),不能调用子类中的特有成员
    编译阶段 调用哪些方法是编译类型决定的,比如animal想调用Cat类特有的catchMouse()方法编译报错
    运行阶段 调用是先从子类开始的,遵循方法调用规则

  • 向下转型
    子类类型 引用名 = (子类类型)父类引用;
    Cat cat = (Cat) animal;
    cat.catchMouse();
    只能强转父类的引用,不能强转父类的对象
    父类的引用必须指向的是当前目标类型的对象
    Animal animal = new Cat(); //此时的animal指向的是Cat
    Cat cat = (Cat) animal; //这样才能向下转型成Cat 如果是转成Dog类 不对
    向下转型后,可以调用子类类型中所有的成员

  • 属性不重写,属性的值看编译类型

public class Poly01 {
    public static void main(String[] args) {
        //属性没有重写之说!属性的值看编译类型
        Base base = new Sub();//向上转型
        System.out.println(base.count);// ? 看编译类型 10
        Sub sub = new Sub();
        System.out.println(sub.count);//? 20
    }
}

class Base {
    //父类 
    int count = 10;//属性 
}

class Sub extends Base {

    //子类
    int count = 20;//属性 }
}
  • instanceOf 比较操作符,用于判断对象的运行类型是否为 XX 类型或 XX 类型的子类型
  • 动态绑定机制
    当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
    当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用
public class DynamicBinding {
    public static void main(String[] args) {
        //a 的编译类型 A, 运行类型 B
        A a = new B();//向上转型
        System.out.println(a.sum());//?40 -> 30
        System.out.println(a.sum1());//?30-> 20
    }
}

class A {//父类
    public int i = 10;
    //动态绑定机制:

    public int sum() {//父类sum()
        return getI() + 10;//20 + 10
    }

    public int sum1() {//父类sum1()
        return i + 10;//10 + 10
    }

    public int getI() {//父类getI
        return i;
    }
}

class B extends A {//子类
    public int i = 20;

//    public int sum() {
//        return i + 20;
//    }

    public int getI() {//子类getI()
        return i;
    }

//    public int sum1() {
//        return i + 10;
//    }
}

  • 多态数组
    数组的定义类型为父类类型,里面保存的实际元素为子类类型
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;
    }
}
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;
    }

    @Override
    public String say(){
        return super.say() + "score=" + score;
    }
    public void study(){
        System.out.println(getName()+"正在学习");
    }
}

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;
    }

    @Override
    public String say(){
        return super.say()+"salary="+salary;
    }
    public void teach(){
        System.out.println(getName()+"正在讲课");
    }
}
public class PolyArray {
    public static void main(String[] args) {
        Person[] persons = new Person[5];
        persons[0] = new Person("jack",20);
        persons[1] = new Student("jack",18,100);
        persons[2] = new Student("smith",19,30.1);
        persons[3] = new Teacher("s",30,20000);
        persons[4] = new Teacher("king",50,25000);

        //循环遍历多态数组,调用say()
        for(int i = 0;i < persons.length;i++){
            System.out.println(persons[i].say());//动态绑定,编译类型是Person,运行类型根据实际情况
            if(persons[i] instanceof Student){ //运行类型是不是Student
                ((Student)persons[i]).study(); //向下转型
            } else if(persons[i] instanceof Teacher){
                Teacher teacher = (Teacher) persons[i];
                teacher.teach();
            } else if(persons[i] != null){
                System.out.println("");
            }else{
                System.out.println("类型有误");
            }
        }
    }
}
  • 多态参数
    形参为父类类型,实参为子类类型
public class Employee {
    private String name;
    private double salary;

    public Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    public double getAnnual() {
        return 12.0D * this.salary;
    }

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

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

    public double getSalary() {
        return this.salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }
}
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 this.bonus;
    }

    public void setBonus(double bonus) {
        this.bonus = bonus;
    }

    public void manage() {
        System.out.println("经理 " + this.getName() + " is managing");
    }

    public double getAnnual() {
        return super.getAnnual() + this.bonus;
    }
}
public class Worker extends Employee {
    public Worker(String name, double salary) {
        super(name, salary);
    }

    public void work() {
        System.out.println("普通员工 " + this.getName() + " is working");
    }

    public double getAnnual() {
        return super.getAnnual();
    }
}
public class PloyParameter {
    public PloyParameter() {
    }

    public static void main(String[] args) {
        Worker tom = new Worker("tom", 2500.0D);
        Manager milan = new Manager("milan", 5000.0D, 200000.0D);
        PloyParameter ployParameter = new PloyParameter();
        ployParameter.showEmpAnnual(tom);
        ployParameter.showEmpAnnual(milan);
        ployParameter.testWork(tom);
        ployParameter.testWork(milan);
    }

    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("");
        }

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值