39-面向对象编程(基础)3
方法重载
基本介绍
java中允许同一个类中,多个同名方法的存在,但要求形参列表一致
比如:System.out.println() ; out 是printStream类
重载的好处
- 减轻了起名的麻烦
- 减轻了记名的麻烦
快速入门
public class OverLoad01 {
//编写一个main方法
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);
//
MyCalculator mc = new MyCalculator();
System.out.println(mc.calculate(1, 2));
System.out.println(mc.calculate(1.1, 2));
System.out.println(mc.calculate(1, 2.1));
}
}
class MyCalculator {
//下面的四个 calculate方法构成了重载
//两个整数的和
public int calculate(int n1, int n2) {
System.out.println("calculate(int n1, int n2) 被调用");
return n1 + n2;
}
//没有构成方法重载, 仍然是错误的,因为是方法的重复定义
// public void calculate(int n1, int n2) {
// System.out.println("calculate(int n1, int n2) 被调用");
// int res = n1 + n2;
// }
//看看下面是否构成重载, 没有构成,而是方法的重复定义,就错了
// public int calculate(int a1, int a2) {
// System.out.println("calculate(int n1, int n2) 被调用");
// return a1 + a2;
// }
//一个整数,一个double的和
public double calculate(int n1, double n2) {
return n1 + n2;
}
//一个double ,一个Int和
public double calculate(double n1, int n2) {
System.out.println("calculate(double n1, int n2) 被调用..");
return n1 + n2;
}
//三个int的和
public int calculate(int n1, int n2,int n3) {
return n1 + n2 + n2;
}
}
注意事项和使用细节
- 方法名:必须相同
- 形参列表:必须不同(形成类型或个数或顺序,至少有一样不同,参数名无要求)
- 返回类型:无要求
eg:
可变参数
基本概念
java允许将同一个类中多个同名功能但参数个数不同的方法,封装成一个方法,就可以通过可变参数实现
基本语法
访问修饰符 返回类型 方法名(数据类型... 参数名){
}
快速入门
public class VarParameter01 {
//编写一个main方法
public static void main(String[] args) {
HspMethod m = new HspMethod();
System.out.println(m.sum(1, 5, 100)); //106
System.out.println(m.sum(1,19)); //20
}
}
class HspMethod {
//可以计算 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 += nums[i];
}
return res;
}
}
使用细节
- 可变参数的实参可以为0个或者任意个
- 可变参数的实参可以为数组
- 可变参数的本质就是数组
- 可变参数可以和普通类型的参数放在形参列表,但必须保证可变参数在最后
- 一个形参列表中只能出现一个可变参数
public class VarParameterDetail {
//编写一个main方法
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(String str, double... nums) {
}
//细节: 一个形参列表中只能出现一个可变参数
//下面的写法是错的.
// public void f3(int... nums1, double... nums2) {
// }
}
练习
public class VarParameterExercise {
//编写一个main方法
public static void main(String[] args) {
HspMethod hm = new HspMethod();
System.out.println(hm.showScore("milan" , 90.1, 80.0 ));
System.out.println(hm.showScore("terry" , 90.1, 80.0,10,30.5,70 ));
}
}
class HspMethod {
/*
有三个方法,分别实现返回姓名和两门课成绩(总分),
返回姓名和三门课成绩(总分),返回姓名和五门课成绩(总分)。
封装成一个可变参数的方法
*/
//分析1. 方法名 showScore 2. 形参(String ,double... ) 3. 返回String
//听课小伙伴,老师要求必须自己动手写
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;
}
}
作用域
基本介绍
public class VarScope {
//编写一个main方法
public static void main(String[] args) {
}
}
class Cat {
//全局变量:也就是属性,作用域为整个类体 Cat类:cry eat 等方法使用属性
//属性在定义时,可以直接赋值
int age = 10; //指定的值是 10
//全局变量(属性)可以不赋值,直接使用,因为有默认值,
double weight; //默认值是0.0
public void hi() {
//局部变量必须赋值后,才能使用,因为没有默认值
int num = 1;
String address = "北京的猫";
System.out.println("num=" + num);
System.out.println("address=" + address);
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的变量 name=" + name);//错误
}
}
细节
- 属性和局部变量可以重名,访问时遵循就近原则
- 在同一个作用域中,比如在同一个方法中,两个局部变量,不能重名
- 属性生命周期长,伴随着对象的创建二创建,伴随对象的销毁而销毁。局部变量,生命周期短,伴随着它的代码块的执行而创建,伴随这代码块的结束而销毁。即在一次方法调用的过程中
- 作用域范围不同
全局变量/属性:可以被本类使用,或其他类使用(通过对象调用)
局部变量:只能在本类中对应的方法使用 - 修饰符不同
全局变量/属性可以加修饰符
局部变量不可以加修饰符
public class VarScopeDetail {
//编写一个main方法
public static void main(String[] args) {
Person p1 = new Person();
/*
属性生命周期较长,伴随着对象的创建而创建,伴随着对象的销毁而销毁。
局部变量,生命周期较短,伴随着它的代码块的执行而创建,
伴随着代码块的结束而销毁。即在一次方法调用过程中
*/
//p1.say();//当执行say方法时,say方法的局部变量比如name,会创建,当say执行完毕后
//name局部变量就销毁,但是属性(全局变量)仍然可以使用
//
T t1 = new T();
t1.test(); //第1种跨类访问对象属性的方式
t1.test2(p1);//第2种跨类访问对象属性的方式
}
}
class T {
//全局变量/属性:可以被本类使用,或其他类使用(通过对象调用)
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 {
//细节: 属性可以加修饰符(public protected private..)
// 局部变量不能加修饰符
public int age = 20;
String name = "jack";
public void say() {
//细节 属性和局部变量可以重名,访问时遵循就近原则
String name = "king";
System.out.println("say() name=" + name);
}
public void hi() {
String address = "北京";
//String address = "上海";//错误,重复定义变量
String name = "hsp";//可以
}
}
构造器
基本介绍
基本语法
快速入门
public class Constructor01 {
//编写一个main方法
public static void main(String[] args) {
//当我们new 一个对象时,直接通过构造器指定名字和年龄
Person p1 = new Person("smith", 80);
System.out.println("p1的信息如下");
System.out.println("p1对象name=" + p1.name);//smith
System.out.println("p1对象age=" + p1.age);//80
}
}
//在创建人类的对象时,就直接指定这个对象的年龄和姓名
//
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;
}
}
使用细节
public class ConstructorDetail {
//编写一个main方法
public static void main(String[] args) {
Person p1 = new Person("king", 40);//第1个构造器
Person p2 = new Person("tom");//第2个构造器
Dog dog1 = new Dog();//使用的是默认的无参构造器
}
}
class Dog {
//如果程序员没有定义构造器,系统会自动给类生成一个默认无参构造器(也叫默认构造器)
//使用javap指令 反编译看看
/*
默认构造器
Dog() {
}
*/
//一旦定义了自己的构造器,默认的构造器就覆盖了,就不能再使用默认的无参构造器,
//除非显式的定义一下,即: Dog(){} 写 (这点很重要)
//
public Dog(String dName) {
//...
}
Dog() { //显式的定义一下 无参构造器
}
}
class Person {
String name;
int age;//默认0
//第1个构造器
public Person(String pName, int pAge) {
name = pName;
age = pAge;
}
//第2个构造器, 只指定人名,不需要指定年龄
public Person(String pName) {
name = pName;
}
}
练习
public class ConstructorExercise {
//编写一个main方法
public static void main(String[] args) {
Person p1 = new Person();//无参构造器
//下面输出 name = null, age = 18
System.out.println("p1的信息 name=" + p1.name + " age=" + p1.age);
Person p2 = new Person("scott", 50);
//下面输出 name = scott, age = 50
System.out.println("p2的信息 name=" + p2.name + " age=" + p2.age);
}
}
/**
* 在前面定义的Person类中添加两个构造器:
* 第一个无参构造器:利用构造器设置所有人的age属性初始值都为18
* 第二个带pName和pAge两个参数的构造器:
* 使得每次创建Person对象的同时初始化对象的age属性值和name属性值。
* 分别使用不同的构造器,创建对象.
*/
class Person {
String name;//默认值 null
int age;//默认 0
//第一个无参构造器:利用构造器设置所有人的age属性初始值都为18
public Person() {
age = 18;//
}
//第二个带pName和pAge两个参数的构造器
public Person(String pName, int pAge) {
name = pName;
age = pAge;
}
}
对象创建流程详解
This关键字
基本介绍
java虚拟机会给每个对象分配this,代表当前对象
public class This01 {
//编写一个main方法
public static void main(String[] args) {
Dog dog1 = new Dog("大壮", 3);
System.out.println("dog1的hashcode=" + dog1.hashCode());
//dog1调用了 info()方法
dog1.info();
System.out.println("============");
Dog dog2 = new Dog("大黄", 2);
System.out.println("dog2的hashcode=" + dog2.hashCode());
dog2.info();
}
}
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){//构造器
//this.name 就是当前对象的属性name
this.name = name;
//this.age 就是当前对象的属性age
this.age = age;
System.out.println("this.hashCode=" + this.hashCode());
}
public void info(){//成员方法,输出属性x信息
System.out.println("this.hashCode=" + this.hashCode());
System.out.println(name + "\t" + age + "\t");
}
}
this本质
小结:简单的说,哪个对象调用,this就代表哪个对象
this使用细节
- this关键字可以用来访问本类的属性,方法,构造器
- this用于区分当前类的属性和局部变量
- 访问成员方法的语法:this.方法名(形参列表);
- 访问构造器方法:this(形参列表);
(注意:只能在构造器中访问另一个构造器,必须放在第一条语句) - this 不能在类定义的外部使用,只能在类定义的方法中使用
public class ThisDetail {
//编写一个main方法
public static void main(String[] args) {
// T t1 = new T();
// t1.f2();
T t2 = new T();
t2.f3();
}
}
class T {
String name = "jack";
int num = 100;
/*
细节: 访问构造器语法: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 f3() {
String name = "smith";
//传统方式
System.out.println("name=" + name + " num=" + num);//smith 100
//也可以使用this访问属性
System.out.println("name=" + this.name + " num=" + this.num);//jack 100
}
//细节: 访问成员方法的语法:this.方法名(参数列表);
public void f1() {
System.out.println("f1() 方法..");
}
public void f2() {
System.out.println("f2() 方法..");
//调用本类的 f1
//第一种方式
f1();
//第二种方式
this.f1();
}
}
练习
public class TestPerson {
//编写一个main方法
public static void main(String[] args) {
Person p1 = new Person("mary", 20);
Person p2 = new Person("mary", 20);
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;
}
}
最后
附上韩顺平老师这节内容的章节总结原视频有助于知识梳理
进度263/910 ,学习永无止境!!!