一、关键字:this
1.1 this是什么?
我们在声明一个属性对应的setXxx方法时,通过形参给对应的属性赋值。如果形参名和属性名同名了,那么该如何在方法内区分这两个变量呢?
解决方案:使用this。具体来讲,使用this修饰的变量,表示的是属性。没有用this修饰的,表示的是形参。
this可以调用的结构:成员变量、方法、构造器
this的理解:当前对象(在方法中调用)或当前正在创建的对象(在构造器中调用)
1.2 this调用属性和方法
一般情况:通过对象调用方法,可以在方法内调用当前对象的属性或者其他方法。此时,我们可以在属性和其他方法前使用“this.”,表示当前属性或者方法所属的对象。但是,一般情况下,我们都选择省略此“this.”结构。
特殊情况:如果方法的形参与对象的属性重名了,我们必须使用this.进行区分。使用this.修饰的变量即为属性(或成员变量);没有使用this.修饰的变量,即为局部变量。
针对构造器:一般情况:我们通过构造器创建对象时,可以在构造器内调用当前正在创建的对象的属性或者方法。此时,我们可以在属性和其他方法前使用“this.”,表示当前属性或者方法所属的对象。但是,一般情况下,我们都选择省略此“this.”结构。
特殊情况:如果构造器的形参与正在创建的对象的属性重名了,我们必须使用this.进行区分。使用this.修饰的变量即为属性(或成员变量);没有使用this.修饰的变量,即为局部变量。
package com.atguigu01_this;
/**
* package:com.atguigu01
*
* @Author jimmy-yan
* @Create 2024/10/16 10:51
*/
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.setAge(10);
System.out.println(p1.age);
p1.sleep();
}
}
class Person {
String name;
int age;
public void setAge(int age) {
this.age = age;
}
public void eat(){
System.out.println("吃");
}
public void sleep(){
System.out.println("睡");
this.eat();
}
}
1.3 this调用构造器
格式:“this(形参列表)” 格式
我们可以使用 “this(形参列表)” 格式,调用当前类中指定的其他构造器。
要求:“this(形参列表)” 必须声明当前构造器的首行。
结论:“this(形参列表)” 在构造器中最多声明一个
如果一个类中声明了n个构造器,则最多有n-1个构造器可以声明::“this(形参列表)” ,避免出现递归
package com.atguigu01_this.exec1;
public class Boy {
private String name;
private int 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 Boy(){
}
public Boy(String name, int age) {
this.name = name;
this.age = age;
}
public void marry(Girl girl){
System.out.println("娶"+ girl.getName());
}
public void shout(){
if (age>=22){
System.out.println("可以结婚");
}else{
System.out.println("谈");
}
}
}
package com.atguigu01_this.exec1;
public class Girl {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Girl() {
}
public Girl(String name, int age) {
this.name=name;
this.age=age;
}
public void marry(Boy boy) {
System.out.println("嫁给" + boy.getName());
boy.marry(this);
}
public int compare(Girl girl) {
if (this.age < girl.age) {
return 1;
} else if (this.age > girl.age) {
return -1;
} else {
return 0;
}
}
}
package com.atguigu01_this.exec1;
public class BGTest {
public static void main(String[] args) {
Boy boy1 = new Boy("杰克", 24);
Girl girl1 = new Girl("朱丽叶", 20);
girl1.marry(boy1);
}
}
二、面向对象的特征之三:继承性
2.1 继承的好处
继承的出现减少了代码冗余,提高代码的复用性。
继承的出现,更有利于功能的拓展。
继承的出现让类与类之间产生is-a的关系,为多态的使用提供了前提。
2.2 格式
class A{
//属性、方法
}
class B extends A{
}
类A:父类、基类、超类
类B:子类、派生类
1、有了继承性以后:子类就获取了父类的属性和方法。
2、但是,由于封装性的影响,可能子类不能直接调用父类中声明的属性或者方法(private)。
3、子类在继承父类以后,还可以拓展自己特有的功能。
4、java中声明的类,如果没有显示的声明其父类时,则默认继承于java.lang.Object
5、java是支持多层继承;直接父类、间接父类;子类父类是相对的。
java中一个父类可以声明多个子类。反之,一个类只能有1个父类(java的单继承性)
案例1
package atguigu03_extends;
public class Person {
String name;
int age;
public void eat() {
System.out.println("吃饭");
}
}
package atguigu03_extends;
public class Student extends Person {
String name;
int age;
String school;
// public void eat(){
// System.out.println("吃饭");
// }
// public void stady(){
// System.out.println("study");
// }
}
package atguigu03_extends;
public class ExtendsTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.name = "Tom";
p1.eat();
Student s1 = new Student();
s1.name = "jimmy";
s1.eat();
System.out.println(s1.toString());
}
}
案例2
(1)定义一个ManKind类,包括成员变量int sex和int salary;
方法void manOrWoman():根据sex的值显示"man"(sex==1)
或者"woman”(sex==0)
;
方法void employeed():根据salary的值显示"no job"(salary==0
)或者”job"(salary!=0)
(2)定义类Kids继承ManKind,
并包括成员变量int yearsOld;
方法printAge()打印yearsOld的值。
(3)定义类KidsTest,在类的main方法中实例化Kids的对象someKid,用该对象访问其父类的成员变量及方法。
package atguigu03_extends.exec1;
public class ManKind {
private int sex;
private int salary;
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public ManKind() {
}
public ManKind(int sex, int salary) {
this.sex = sex;
this.salary = salary;
}
public void manOrWoman() {
if (sex == 1) {
System.out.println("man");
} else {
System.out.println("woman");
}
}
public void employeed() {
if (salary == 0) {
System.out.println("no job");
} else {
System.out.println("job");
}
}
}
package atguigu03_extends.exec1;
public class Kids extends ManKind {
private int yearsOld;
public int getYearsOld() {
return yearsOld;
}
public Kids() {
}
public Kids(int yearsOld) {
this.yearsOld = yearsOld;
}
public void setYearsOld(int yearsOld) {
this.yearsOld = yearsOld;
}
public void printAge() {
System.out.println("yearOld的值为:" + yearsOld);
}
}
package atguigu03_extends.exec1;
public class KidsTest {
public static void main(String[] args) {
Kids kids = new Kids();
kids.setSex(1);
kids.setSalary(1000);
kids.setYearsOld(6);
kids.employeed(); //job
kids.manOrWoman(); //man
}
}
三、方法的重写
1、四种权限修饰符范围演示
a、在类中,4种权限修饰符全部有效
package test;
/**
* package:test
*
* @Author jimmy-yan
* @Create 2024/10/24 15:13
*/
public class Order {
private int orderPrivate;
int orderDefault;
protected int orderProtected;
public int orderPublic;
private void methodPrivate() {
}
void methodDefault() {
}
protected void methodProtected() {
}
public void methodPublic() {
}
//类内部
public void show() {
orderPrivate = 1;
orderDefault = 1;
orderProtected = 1;
orderPublic = 1;
}
}
b、在同一个包下,private是不可以的
package test;
/**
* package:test
*
* @Author jimmy-yan
* @Create 2024/10/24 15:17
*/
public class OrderTest {
public void method1(){
Order order = new Order();
order.orderPublic=1;
order.orderDefault=1;
order.orderProtected=1;
order.methodDefault();
order.methodPublic();
order.methodProtected();
order.methodPrivate();
order.orderPrivate=1;
}
}
受封装性的影响,不能调用
c、跨包默认权限修饰符和private私有权限修饰符不能用
d、其他包非子类下,只有public能用
2、为什么需要方法的重写
子类在继承父类以后,就获取了父类中声明的所有的方法。但是,父类中的方法可能不太适用于子类,换句话说,子类需要对父类中继承过来的方法进行覆盖、覆写的操作。
子类对父类继承过来的方法进行的覆盖、覆写的操作,就是方法的重写。
方法的声明格式
权限修饰符 返回值类型 方法名(形参列表) {//方法体}
3、重写规则
- 父类被重写的方法与子类重写的方法的方法名和参数列表必须相同
- 子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符
- 子类不能重写父类中声明为private权限修饰的方法
- 关于返回值类型:
- 父类被重写的方法的返回值类型是void,则子类重写的返回值类型也必须是void。
- 父类被重写的方法的返回值类型是基本数据类型,则子类重写的方法的返回值类型必须与被重写的方法的返回值类型相同。
- 父类被重写的方法的返回值类型是引用数据类型(比如类),则子类重写的方法的返回值类型可以与被重写的方法的返回值类型相同 或 是被重写的方法的返回值类型的子类。
4、区分方法的重载(overload)与重写(overwrite)
重载:两同一不同
重写:继承以后,子类覆盖父类种同名同参数的方法