【Java】面向对象(基础) - 2

面向对象(基础)

6. 方法重载

基本介绍

java 中允许同一个类中,多个同名方法的存在,但要求形参列表不一致

比如:System.out.println(); out是 PrintStream 类型

重载的好处

  1. 减轻了起名的麻烦
  2. 减轻了记名的麻烦
public class OverLoad01 {
        public static void main(String[] args) {
                System.out.println(100);
                System.out.println("Hello,World");
                System.out.println('h');
                System.out.println(1.1);
                System.out.println(true);
        }
}

练习

public class OverLoad02 {
        public static void main(String[] args) {
                MyCalculator mc = new MyCalculator();

                System.out.println(mc.calculate(1, 2));

                System.out.println(mc.calculate(1, 2.2));

                System.out.println(mc.calculate(1.1, 2));

                System.out.println(mc.calculate(1, 2, 3));

        }
}

class MyCalculator {
        //两个整数的和
        public int calculate(int n1, int n2) {
                System.out.println("public int calculate(int n1, int n2) 被调用");
                return n1 + n2;
        }

        //一个整数,一个double的和
        public double calculate(int n1, double n2) {
                System.out.println("public int calculate(int n1, double n2) 被调用");
                return n1 + n2;
        }

        //一个double,一个int的和
        public double calculate(double n1, int n2) {
                System.out.println("public int calculate(double n1, int n2) 被调用");
                return n1 + n2;
        }

        //三个int的和
        public int calculate(int n1, int n2, int n3) {
                System.out.println("public int calculate(int n1, int n2, int n3) 被调用");
                return n1 + n2 + n3;
        }
}

注意事项和使用细节

  • 方法名:必须相同
  • 参数列表:必须不同(参数类型或个数或顺序,至少有一样不同,参数名无要求)
  • 返回类型:无要求

方法重载练习

判断题:

  1. 与void show(int a,char b,double c){} 构成重载的有:【b、c、d、e、g】

a) void show(int x, char y, double z){}

b) int show(int a,double c.char b){}

c) void show(int a, double c, char b){}

d) boolean show(int c, char b){}

e) void show(double c){}

f) double show(int x, char y, double z){}

g) void shows(){}

程序题

  1. 编写程序,类Methods中定义三个重载方法并调用。

方法名为m。三个方法分别接收一个int参数、两个int参数、一个字符串参数。

分别执行平方运算并输出结果,相乘并输出结果,输出字符串信息。

在主类的main ()方法中分别用参数区别调用三个方法。

public class OverLoad03 {
        public static void main(String[] args) {
                Methods method = new Methods();
                method.m(10);
                method.m(10,10);
                method.m("hello world");
        }
}

/**
 * 1. 编写程序,类Methods中定义三个重载方法并调用。
 * 方法名为m。三个方法分别接收一个int参数、两个int参数、一个字符串参数
。
 * 分别执行平方运算并输出结果,相乘并输出结果,输出字符串信息。
 * 在主类的main ()方法中分别用参数区别调用三个方法。
 * */
class Methods {
        public void m(int n) {
                System.out.println("平方 = " + (n * n));
        }

        public void m(int n1, int n2) {
                System.out.println("相乘 = " + (n1 * n2));
        }

        public void m(String str) {
                System.out.println("传入的 str = " + str);
        }
}
  1. 在Methods类,定义三个重载方法max(),

第一个方法,返回两个int值中的最大值,

第二个方法,返回两个double值中的最大值,

第三个方法,返回三个double值中的最大值,

并分别调用三个方法。

public class OverLoad04 {
        public static void main(String[] args) {
                Methods method = new Methods();
                System.out.println(method.max(10, 20));
                System.out.println(method.max(1.1, 2.2));
                System.out.println(method.max(1.1, 2.2, 3.3));
        }
}

/**
 * 2. 在Methods类,定义三个重载方法max(),
 * 第一个方法,返回两个int值中的最大值,
 * 第二个方法,返回两个double值中的最大值,
 * 第三个方法,返回三个double值中的最大值,
 * 并分别调用三个方法。
 *
 * */
class Methods {
        public int max(int n1, int n2) {
                return n1 > n2 ? n1 : n2;
        }

        public double max(double n1, double n2) {
                return n1 > n2 ? n1 : n2;
        }

        public double max(double n1, double n2, double n3) {
                double max = n1 > n2 ? n1 : n2;
                return max > n3 ? max : n3;
        }
}

7. 可变参数

  • 基本概念

java允许将同一个类中 多个同名 同功能参数个数不同 的方法,封装成一个方法。

  • 基本语法
访问修饰符 返回类型 方法名(数据类型... 形参名) {

}
public class VarParameter01 {
        public static void main(String[] args) {
                Method method = new Method();
                System.out.println(method.sum(1, 5, 100));
        }
}

class Method {
        //可以计算 2个数的和,3个数的和,4,5...
        //可以使用方法重载
        //public int sum(int n1, int n2) {      //2个数的和
        //      return n1 + n2;
        //}

        //public int sum(int n1, int n2, int n3) {      //3个数的和
        //      return n1 + n2 + n3;
        //}

        //public int sum(int n1, int n2, int n3, int n4) {      //4个数的和
        //      return n1 + n2 + n3 + n4;
        //}

        //...
        //上面的三个方法名称相同,功能相同,参数个数不同 -> 使用可变参数优化
        //1. int... 表示接受的是可变参数,类型是int,即可以接收多个int(0-多)
        //2. 使用可变参数时,可以当作数组来使用,即 nums 可以当作数组
        //3. 遍历 nums 求和即可
        public int sum(int... nums) {
                //System.out.println("接收的参数个数=" + nums.length);
                int res = 0;
                for (int i = 0; i < nums.length; i++) {
                        res += num[i];
                }

                return res;
        }
}
  • 注意事项和使用细节
  1. 可变参数的实参可以为0个或任意多个。
  2. 可变参数的实参可以为数组。
  3. 可变参数的本质就是数组。
  4. 可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数在最后
  5. 一个形参列表中只能出现一个可变参数
public class VarParameter02 {
	public static void main(String[] args) {
		//细节:可变参数的实参可以为数组
		int[] arr = {1,2,3};
		T t1 = new T();
		t1.f1(arr);
	}
}

class T {
	public void f1(int... nums) {
		System.out.println("长度=" + nums.length);		
	}

	//可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数在最后
	//public void f2(double... nums, String str) {}	//编译出错,因为可变参数没放在其他类型的参数后面
	//
	//编译没出错
	public void f2(String str, double... nums) {
		
	}

	//细节:一个形参列表中只能出现一个可变参数
	//
	//public void f3(int... nums1, double... nums2) {}	//编译报错
	//
	//编译没报错
	public void f3(int... nums){}
}

可变参数练习

有三个方法,分别实现返回姓名和两门课成绩(总分),返回姓名和三门课成绩(总分),返回姓名和五门课成绩(总分)。
封装成一个可变参数的方法。

public class VarParameter03 {
        public static void main(String[] args) {
                Method m = new Method();
                System.out.println(m.showScore("milan", 90.1, 80.0));
                System.out.println(m.showScore("terry", 90.1, 80.0, 10, 30.5, 70));
        }
}

class Method {
        /*
        * 有三个方法,
        * 分别实现返回姓名和两门课成绩(总分),
        * 返回姓名和三门课成绩(总分),
        * 返回姓名和五门课成绩(总分)。
        * 封装成一个可变参数的方法。
        * */
        public String showScore(String name, double... scores) {
                double totalScore = 0;
                for (int i = 0; i < scores.length; i++) {
                        totalScore += scores[i];
                }
                return name + " 有 " + scores.length + "门课的成绩总分为=" + totalScore;
        }
}

8. 作用域

基本介绍

  1. 在 java 编程中,主要的变量就是属性(成员变量)和局部变量。
  2. 局部变量一般是指在成员方法中定义的变量。
  3. java 中作用域的分类
    1. 全局变量:也就是属性,作用域为整个类体。Cat类: cry eat等方法使用属性。
    2. 局部变量:也就是除了属性之外的其他变量,作用域为定义它的代码块中!
  4. 全局变量可以不赋值,直接使用,因为有默认值,局部变量必须赋值后,才能使用,因为没有默认值。
public class VarScope01 {
        public static void main(String[] args) {

        }
}

class Cat {
        //全局变量:也就是属性,作用域为整个类体 Cat类:cry eat 等方法使用属性
        //属性在定义时,可以直接赋值
        int age = 10;   //指定的值是 10

        //全局变量可以不赋值,直接使用,因为有默认值。
        double weight;  //默认值是0.0

        //局部变量必须赋值后,才能使用,因为没有默认值。
        public void hi() {
                //int num;      //全局变量不赋值,编译时报错
                int num = 1;
                //String address;       //全局变量不赋值,编译时报错
                String addrees = "外面的猫";
                System.out.println("num=" + num);
                System.out.println("addrees=" + addrees);
                System.out.println("weight=" + weight);
        }

        public void cry() {
                //1.局部变量一般是指在成员方法中定义的变量
                //2.n 和 name 就是局部变量
                //3.n 和 name 的作用域在 cry方法中
                int n = 10;
                String name = "jack";
                System.out.println("在 cry 中使用属性 age = " + age);   //没报错
        }

        public void eat() {
                System.out.println("在 eat 中使用属性 age = " + age);   //没报错
                //System.out.println("在 eat 中使用属性 cry = " + cry); //报错
        }
}

注意事项和细节使用

  • 属性和局部变量可以重名,访问时遵循就近原则

  • 在同一个作用域中,比如在同一个成员方法中,两个局部变量,不能重名。

  • 属性生命周期较长,伴随着对象的创建而创建,伴随着对象的销毁而销毁。

  • 局部变量,生命周期较短,伴随着它的代码块的执行而创建,伴随着代码块的结束而销毁。即在一次方法调用过程中。

public class VarScopr02 {
        public static void main(String[] args) {
                Person p1 = new Person();
                p1.say();       
                //当执行say方法时,say方法的局部变量比如name,会创建,当say执行完毕后
                //name局部变量就销毁,但是属性(全局变量)仍然可以使用
        }
}

class Person {
        String name = "jack";

        public void say() {
                //细节:属性和局部变量可以重名,访问时遵循就近原则
                String name = "king";                System.out.println("say() name = " + name);     //输出的是king
        }

        public void hi() {
                String address = "北京";
                //String address = "上海";      //重复定义
                String name = "tom";    //可以
        }
}
  • 作用域范围不同
    • 全局变量/属性:可以被本类使用,或其他类使用(通过对象调用)
    • 局部变量:只能在本类中对应的方法中使用
  • 修饰符不同
    • 全局变量/属性可以加修饰符
    • 局部变量不可以加修饰符
public class VarScope03 {
        public static void main(String[] args) {
                T t1 = new T();
                t1.test();      //jack  //第一种跨类访问对象属性的方式

                Person p1 = new Person();
                t1.test2(p1);   //jack  //第二种跨类访问对象属性的方式
        }
}

class T {
        //全局变量/属性可以加修饰符(public protected private ... )
        private int age = 20;

        //全局变量/属性:可以被本类使用,或其他类使用(通过对象调用)
        public void test() {
                Person p1 = new Person();
                System.out.println(p1.name);    //jack
        }

        public void test2(Person p) {
                System.out.println(p.name);     //jack
        }
}

class Person {
        String name = "jack";

        public void say() {
                //局部变量不可以加修饰符
                //public String name = "king";  //报错
                String name = "king";
        }
}

9. 构造方法/构造器

基本语法

[修饰符] 方法名 (形参列表) {
	方法体;
}
  1. 构造器的修饰符可以默认,也可以是 public protected private …
  2. 构造器没有返回值
  3. 方法名和类名字必须一样
  4. 参数列表和成员方法一样的规则
  5. 构造器的调用系统完成

基本介绍

构造方法又叫构造器(constructor),是类的一种特殊的方法,它的主要作用是完成对新对象的初始化。

构造方法的特点:

  1. 方法名和类名相同
  2. 没有返回值
  3. 在创建对象时,系统会自动的调用该类的构造器完成对对象的初始化。
public class Constructor01 {
        public static void main(String[] args) {
                Person p1 = new Person("smith",80);
                System.out.println("p1信息如下");
                System.out.println("p1对象 name = " + p1.name);
                System.out.println("p1对象 age = " + p1.age);
        }
}

//在创建人类的对象时.就直接指定这个对象的年龄和姓名
class Person {
        String name;
        int age;
        //构造器
        //1. 构造器没有返回值,也不能void
        //2. 构造器的名称和类Person—样
        ///3. (String pName, int pAge) 是构造器形参列表,规则和成员方法一样
        public Person(String pName, int pAge) {
                System.out.println("构造器被调用,完成对象属性初始化");
                name = pName;
                age = pAge;
        }
}

注意事项和使用细节

  1. —个类可以定义多个不同的构造器,即构造器重载
    1. 比如:我们可以再给 Person 类定义一个构造器,用来创建对象的时候,只指定人名,不需要指定年龄
  2. 构造器名和类名要相同
  3. 构造器没有返回值
  4. 构造器是完成对象的初始化并不是创建对象
  5. 在创建对象时,系统自动的调用该类的构造方法
public class Constructor02 {
        public static void main(String[] args) {                //—个类可以定义多个不同的构造器,即构造器重载
                Person p1 = new Person("king",40);      //第一个构造器  
                Person p2 = new Person("tom");  //第二个构造器          
        }
}

class Person {
        String name;
        int age;
        //第一个构造器
        public Person(String pName, int pAge) {
                name = pName;
                age = pAge;
        }
        //第二个构造器,至指定人名,不需要指定年龄
        public Person(String pName) {
                name = pName;
        }

        //构造器名和类名要相同
        //构造器没有返回值
        //public P(String pName) {}     //报错,因为系统认为是一个方法,而不>是构造器,方法需要返回值
}
  1. 如果程序员没有定义构造器,系统会自动给类生成一个默认无参构造器(也叫默认构造器),比如 Dog() {}
public class Constructor03 {
        public static void main(String[] args) {
                Dog d = new Dog();
        }
}

class Dog {
        //如果程序员没有定义构造器,系统会自动给类生成一个默认无参构造器(也叫
默认构造器)
        /**
         *      默认构造器
         *      Dog() {
         *
         *      } 
         *
         * */

}

使用 javap 指令反编译查看 Dog 类

在这里插入图片描述

  1. 一旦定义了自己的构造器,默认的构造器就覆盖了,就不能再使用默认的无参构造器,除非显式的定义一下,即:Dog() {}
public class Constructor03 {
        public static void main(String[] args) {
                Dog d = new Dog();                      //定义自己的构造器后使用默认的无参构造器,系统会报错
                //除非显式定义 Dog(){}
        }
}

class Dog {
        //如果程序员没有定义构造器,系统会自动给类生成一个默认无参构造器(也叫
默认构造器)
        /**
         *      默认构造器
         *      Dog() {
         *
         *      } 
         *
         * */

        //一旦定义了自己的构造器,默认的构造器就覆盖了,
        //就不能再使用默认的无参构造器,除非显式的定义一下
        public Dog(String dName) {
                //...
        }

        Dog() { //显式的定义一下
        
        }
}

使用javap指令反编译看看

在这里插入图片描述

练习

public class Constructor04 {
        public static void main(String[] args) {
                Person p1 = new Person();       //无参构造器
                System.out.println("p1 的信息 name = " + p1.name);      //null
                System.out.println("p1 的信息 age = " + p1.age);        //18
                Person p2 = new Person("tom", 20);      //带参数的构造器
                System.out.println("p2 的信息 name = " + p2.name);      //null
                System.out.println("p2 的信息 age = " + p2.age);        //18
        }
}

/**
 * 在前面定义的Person类中添加两个构造器:
 * 第一个无参构造器:利用构造器设置所有人的age属性初始值都为18
 * 第二个带pName和pAge两个参数的构造器:
 * 使得每次创建Person对象的同时初始化对象的age属性值和name属性值。
 * 分别使用不同的构造器,创建对象.
 *
 * */
class Person {
        String name;
        int age;

        //第一个无参构造器:利用构造器设置所有人的age属性初始值都为18
        public Person() {
                age = 18;
        }

        //第二个带pName和pAge两个参数的构造器
        public Person(String pName, int pAge) {
                name = pName;
                age = pAge;
        }
}

10. 对象创建的流程分析

class Person { //类Person
        String name;
        int age;
        public Person(String pName, int pAge) {	//构造器
                name = n;//给属性赋值
                age = a;
        }
}

Person p = new Person("tom",20);

流程分析

  1. 加载 Person 类信息(Person.class),只会加载一次
  2. 在堆中分配空间(地址)
  3. 完成对象初始化
    1. 默认初始化 age = 0 name = null
    2. 显式初始化 age = 90,name = null
    3. 构造器的初始化 age = 20,name = tom
  4. 把对象在堆中的地址,返回给p(p是对象名,也可以理解是对象的引用)

在这里插入图片描述

11. this 关键字

11.1 引出this

public class This01 {
        public static void main(String[] args) {
                Dog dog1 = new Dog("大壮", 3);
                dog1.info();    
                //输出的不是 大壮 和 3 ,而是 null 和 0
        }
}

class Dog {     //类
        String name;
        int age;

        //public Dog(String dName, int dAge) {  //构造器
        //      name = dName;
        //      age = dAge;
        //}
        //
        // 如果我们构造器的形参,能够直接写成属性名,就更好了        
        // 但是出现了一个问题,根据变量的作用域原则
        // 构造器的 name 是局部变量,而不是属性
        // 构造器的 age 是局部变量,而不是属性
        // ==>  引出this关键字来解决
        public Dog(String name, int age) {      //构造器
                name = name;    //null
                age = age;      //0
        }

        public void info() {    //成员方法,输出属性 * 信息
                System.out.println(name + "\t" + age + "\t");
        }
}

11.2 什么是 this

java虚拟机会给每个对象分配this,代表当前对象。

public class This01 {
        public static void main(String[] args) {
                //Dog dog1 = new Dog("大壮", 3);
                //dog1.info();  
                //输出的不是 大壮 和 3 ,而是 null 和 0
                //
                Dog dog1 = new Dog("大壮", 3);
                dog1.info();
            	//输出的是 大壮 和 3 
        }
}

class Dog {     //类
        String name;
        int age;

        //public Dog(String dName, int dAge) {  //构造器
        //      name = dName;
        //      age = dAge;
        //}
        //
        // 如果我们构造器的形参,能够直接写成属性名,就更好了
        // 但是出现了一个问题,根据变量的作用域原则
        // 构造器的 name 是局部变量,而不是属性
        // 构造器的 age 是局部变量,而不是属性
        // ==>  引出this关键字来解决
        //
        //public Dog(String name, int age) {    //构造器
        //      name = name;    //null
        //      age = age;      //0
        //}
        public Dog(String name, int age) {      //构造器
                //this.name 就是当前对象的属性 name
                this.name = name;
                //this.age 就是当前对象的属性 age
                this.age = age;         
        }

        public void info() {    //成员方法,输出属性 * 信息
                System.out.println(name + "\t" + age + "\t");
        }
}

this 的本质

哪个对象调用,this就代表哪个对象

public class This02 {
        public static void main(String[] args) {
                Dog dog1 = new Dog("大壮", 3);
                dog1.info();
                System.out.println("main:dog1.hashCode是:" + dog1.hashCode());        //使用hashCode() 查看对象的情况
        }
}

class Dog {     //类
        String name;
        int age;

        public Dog(String name, int age) {      //构造器
                //this.name 就是当前对象的属性 name
                this.name = name;
                //this.age 就是当前对象的属性 age
                this.age = age;

                System.out.println("构造器:this.hashCode是:" + this.hashCode());      //使用hashCode() 查看对象的情况
        }

        public void info() {
                System.out.println("info:this.hashCode是:" + this.hashCode());        //使用hashCode() 查看对象的情况
        }
}

在这里插入图片描述

11.3 this的注意事项和使用细节

  1. this 关键字可以用来访问本类的属性、方法、构造器
  2. this用于区分当前类的属性和局部变量
  3. 访问成员方法的语法:this.方法名(参数列表);
  4. 访问构造器语法:this(参数列表); 注意只能在构造器中使用this(即只能在构造器中访问另外一个构造器)
    1. 注意:访问构造器语法:this(参数列表); 必须放置第一条语句
  5. 不能在类定义的外部使用,只能在类定义的方法中使用。
public class This03 {
        public static void main(String[] args) {
                System.out.println("f2()方法 去调用本类的 f1() 方法");
                T t1 = new T();
                t1.f2();

                System.out.println("构造器 去访问另一个构造器");
                T t2 = new T();

                System.out.println("访问属性");
                T t3 = new T();
                t3.f3();
        }
}

class T {

        String name = "tom";
        int age = 10;

        /**
        * 访问构造器语法:this(参数列表); 
        * 注意只能在构造器中使用this
        * (即只能在构造器中访问另外一个构造器)
        *
        * 注意:访问构造器语法:this(参数列表); 必须放置第一条语句
        *
        * */
        public T() {
                //这里去访问 T(String name, int age)
                this("jack", 100);

                System.out.println("T() 构造器");
        }

        public T(String name, int age) {
                System.out.println("T(String name, int age) 构造器");
        }

        //访问成员方法的语法:this.方法名(参数列表);
        public void f1() {
                System.out.println("f1() 方法...");
        }

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

        public void f3() {
                //使用传统方式访问属性
                System.out.println("name = " + name + " age = " + age);
                //使用this访问属性
                System.out.println("name = " + this.name + " age = " + this.age);
        }
}

11.4 this 练习

public class This04 {
        public static void main(String[] args) {
                Person p1 = new Person("mary", 20);
                Person p2 = new Person("smith", 30);


                System.out.println("p1 和 p2 比较的结果 = " + p1.compareTo(p2));
        }
}

/**
 * 定义Person类,里面有name、age属性,
 * 并提供compareTo比较方法,用于判断是否和另一个人相等,
 * 提供测试类TestPerson用于测试,
 * 名字和年龄完全一样,就返回true,否则返回false
 *
 * */
class Person {
        String name;
        int age;

        //构造器
        public Person(String name, int age) {
                this.name = name;
                this.age = age;
        }

        //compareTo 比较方法
        public boolean compareTo(Person p) {
                //名字和年龄完全一样
                //if (this.name.equals(p.name) && this.age == p.age) {
                //      return true;
                //} else {
                //      return false;
                //}
                //
                //简化代码
                return this.name.equals(p.name) && this.age == p.age;
        }
}

GitHub代码
gitee代码

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值