Java笔记_9(面向对象进阶)
Java笔记_9
- 一、面向对象进阶
- 1.1、static-静态属性
- 工具类
- 1.2、static的注意事项
- 1.3、重新认识main方法
- 1.4、继承的概念
- 1.5、继承的特点和继承体系的设计
- 1.6、子类到底能继承父类中的那些内容
- 1.7、继承中成员变量和成员方法的访问特点
- 1.8、利用方法的重写设计继承结构
- 1.9、继承中的构造方法
- 1.10、this super关键字
- 1.11、练习-带有继承结构的标准JavaBean类
- 1.11、认识多态
- 1.12、多态中调用成员的特点
- 1.13、多态的优势和弊端
- 1.13、多态的综合练习
- 1.14、包和final
- final
- 1.15、权限修饰符
- 1.16、代码块
- 1.17、抽象类和抽象方法
- 1.18、接口
- 1.19、接口的细节
- 1.19、练习-编写带有接口和抽象类的标准JavaBean类
一、面向对象进阶
1.1、static-静态属性
static表示静态,是Java中的一个修饰符,可以修饰成员方法,成员变量
-
被static修饰的成员变量,叫做静态变量
- 特点:
- 被该类所有对象共享
- 跟对象无关,随着类的加载而加载,优先于对象存在
- 调用方式:
- 类名调用(推荐)
- 对象名调用
- 特点:
-
被static修饰的成员方法,叫做静态方法
- 特点:
- 多用在测试类和工具类中
- Javabean类中很少会用
- 调用方式:
- 类名调用(推荐)
- 对象名调用
- 特点:
类
- JavaBean类
- 用来描述一类事物的类。比如,Student,Teacher,Dog,Cat等
- 测试类
- 用来检查其他类是否书写正确,带有main方法的类,是程序的入口
- 工具类
- 不是用来描述一类事物的,而是帮我们做一些事情的类。
工具类
- 类名见名知意
- 私有化构造方法
- 方法定义为静态
用工具类构造方法,相当于构造函数,如果定义好了工具类,那么直接再次想要复用方法时,可以直接复制类中的代码。
1.2、static的注意事项
- 静态方法只能访问静态变量和静态方法
- 非静态方法可以访问静态变量或者静态方法,也可以访问非静态的成员变量和非静态的成员方法
- 静态方法中是没有this关键字
总结:
静态方法中,只能访问静态。
非静态方法可以访问所有。
静态方法中没有this关键字
1.3、重新认识main方法
public class Helloworld {
public static void main(String[] args) {
system.out.println( "Helloworld");
}
}
public
: 被JVM调用,访问权限足够大static
:被JVM调用,不用创建对象,直接类名访问因为main方法是静态的,所以测试类中其他方法也需要是静态的。void
:被JVM调用,不需要给JVM返回值main
:一个通用的名称,虽然不是关键字,但是被JVM识别String[] args
:以前用于接收键盘录入数据的,现在没用
1.4、继承的概念
封装:对象代表什么,就得封装对应的数据,并提供数据对应的行为
继承:
- Java中提供一个关键字
extends
,用这个关键字,我们可以让一个类和另一个类建立起继承关系。
public class Student/*子类*/ extends Person/*父类*/ {}
- Student称为子类(派生类),Person称为父类(基类或者超类)
使用继承的好处:
- 可以把多个子类中重复的代码抽取到父类中了,提高代码的复用性。
- 子类可以在父类的基础上,增加其他的功能,使子类更强大。
什么时候用继承?
当类与类之间,存在相同(共性)的内容,并满足子类是父类中的一种,就可以考虑使用继承,来优化代码
1.5、继承的特点和继承体系的设计
Java只支持单继承,不支持多继承,但支持多层继承。
- 单继承:一个子类只能继承一个父类
- 不支持多继承:子类不能同时继承多个父类
- 多层继承:子类A继承父类B,父类B可以继承父类C
每一个类都直接或者间接的继承于Object(祖宗类)
总结
- Java只能单继承,不能多继承、但是可以多层继承。
- Java中所有的类都直接或者间接继承于Object类。
- 子类只能访问父类中非私有的成员
1.6、子类到底能继承父类中的那些内容
-
构造方法
- 构造方法不能被子类继承下来
构造方法的方法名需要与类名相同,如果继承下来的话两者就不相同了所以无法继承
- 构造方法不能被子类继承下来
-
成员变量
- 无论是否私有都能被成员变量继承,不过私有的不能直接使用
无private修饰类型:
- 成员方法
1.7、继承中成员变量和成员方法的访问特点
成员变量的访问特点
- 就近原则:谁离得近访问谁
- 先在局部位置找,本类成员位置找,父类成员位置找,逐级往上。
重名:
package entends.aFUzientends;
public class Text{
public static void main(String[] args){
zi z = new zi();
z.ziShow();
}
}
class Fu {
String name = "fu";
}
class zi extends Fu{
String name = "zi";
public void ziShow(){
String name = "zishow";
System.out.println(name);//zishow
System.out.println(this.name);//zi
System.out.println(super.name);//fu
}
}
super指向下会调用父类里面的成员变量
this指向下会调用子类里面的成员变量,如果子类没有就会向父类寻找
没有指向就会采用就近原则来调用变量
成员方法的访问特点
- 直接调用满足就近原则:谁离我近,我就用谁
- super调用,直接访问父类
方法的重写
当父类的方法不能满足子类现在的需求时,需要进行方法重写
书写格式
在继承体系中,子类出现了和父类中一模一样的方法声明,我们就称子类这个方法是重写的方法。
@Override重写注解
-
@Override
是放在重写后的方法上,校验子类重写时语法是否正确。 -
加上注解后如果有红色波浪线,表示语法错误。
-
建议重写方法都加
@Override
注解,代码安全,优雅!
方法重写注意事项和要求- 重写方法的名称、形参列表必须与父类中的一致。
- 子类重写父类方法时,访问权限子类必须大于等于父类(暂时了解 :空着不写< protected < public)
- 子类重写父类方法时,返回值类型子类必须小于等于父类
- 建议:重写的方法尽量和父类保持一致。
- 只有添加到虚方法表中的方法才能被重写
1.8、利用方法的重写设计继承结构
package entends.chongxieAnimal;
public class Text {
public static void main(String[] args) {
hasky dog1 = new hasky();
shapi dog2 = new shapi();
chineseDog dog3 = new chineseDog();
dog1.Eat();
dog2.Eat();
dog3.Eat();
dog1.play();
dog2.drink();
dog3.lookhome();
}
}
package entends.chongxieAnimal;
public class Dog {
public void Eat(){
System.out.println("吃狗粮");
}
public void drink(){
System.out.println("喝水");
}
public void lookhome(){
System.out.println("看家");
}
}
package entends.chongxieAnimal;
public class chineseDog extends Dog{
@Override
public void Eat(){
System.out.println("吃剩饭");
}
}
package entends.chongxieAnimal;
public class hasky extends Dog {
public void play(){
System.out.println("拆家");
}
}
package entends.chongxieAnimal;
public class shapi extends Dog {
@Override
public void Eat(){
super.Eat()
System.out.println("吃骨头);
}
}
1.9、继承中的构造方法
- 父类中的构造方法不会被子类继承
- 子类中所有的构造方法默认先访问父类中的无参构造,再执行自己。
为什么?
- 子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据。
- 子类初始化之前,一定要调用父类构造方法先完成父类数据空间的初始化。
怎么调用父类构造方法的?
- 子类构造方法的第一行语句默认都是: super(),不写也存在,且必须在第一行。
- 如果想调用父类有参构造,必须手动写**super()**进行调用。
public class Person (){
String name;
int age;
pnblic Person(){
System.out.println("父类的无参构造")
}
pnblic Person(String name,int age){
this.name = name;
this.age = age;
}
}
public class Student (){
public Student(){
super();
System.out.println("子类的无参构造")
}
public Student (String name,int age){
super(name,age);
}
}
public class Text(){
public static void main(String[] args){
Student s = new Student(zhangsan,23);
}
}
1.10、this super关键字
- this:理解为一个变量,表示当前方法调用者的地址值;
- super:代表父类存储空间。
关键字 | 访问成员变量 | 访问成员方法 | 访问构造方法 |
---|---|---|---|
this | this.成员变量 访问本类成员变量 | this.成员方法 访问本类成员方法 | this.(…) 访问本类构造方法 |
super | super.成员变量 访问父类成员变量 | super.成员方法 访问父类成员方法 | super.(…) 访问父类构造方法 |
1.11、练习-带有继承结构的标准JavaBean类
package entends.extendsjavabean;
public class text {
Manger a = new Manger(001,"xiaoli",8000,3000);
cooker b = new cooker(002,"xiaowang",8000);
}
package entends.extendsjavabean;
public class Emplyee {
private int num;
private String name;
private int money;
public void work(){
System.out.println("员工在工作");
}
public void eat(){
System.out.println("吃米饭");
}
public Emplyee() {
}
public Emplyee(int num, String name, int money) {
this.num = num;
this.name = name;
this.money = money;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public String toString() {
return "Emplyee{num = " + num + ", name = " + name + ", money = " + money + "}";
}
}
package entends.extendsjavabean;
public class Manger extends Emplyee{
private int boen;
public Manger() {
}
public Manger(int num,String name,int money,int boen) {
super(num,name,money);
this.boen = boen;
}
public int getBoen() {
return boen;
}
public void setBoen(int boen) {
this.boen = boen;
}
public String toString() {
return "Manger{boen = " + boen + "}";
}
@Override
public void work() {
System.out.println("管理别人");
}
}
package entends.extendsjavabean;
public class cooker extends Emplyee{
@Override
public void work() {
System.out.println("炒菜");
}
public cooker(){
}
public cooker(int num,String name,int money){
super(num,name,money);
}
}
1.11、认识多态
什么是多态?
同类型的对象,表现出的不同形态。
多态的表现形式
父类类型 对象名称=子类对象
;
多态的前提
- 有继承关系
- 有父类引用指向子类对象
Fu f = new Zi()
; - 方法重写
多态的好处
使用父类型作为参数,可以接受所有子类对象,体现多态的扩展性与便利
1.12、多态中调用成员的特点
- 变量调用:编译看左边,运行也看左边。
- 编译看左边:javac编译代码的时候,会看左边的父类中有没有这个变量,如果有,编译成功,如果没有编译失败。
- 运行也看左边:java运行代码的时候,实际获取的就是左边父类中成员变量的值
- 方法调用:编译看左边,运行看右边。
- 编译看左边:javac编译代码的时候,会看左边的父类中有没有这个方法,如果有,编译成功,如果没有编译失败。
- 运行看右边: java运行代码的时候,实际上运行的是子类中的方法。
1.13、多态的优势和弊端
优势:
- 在多态形式下,右边对象可以实现解耦合,便于扩展和维护。
- 定义方法的时候,使用父类型作为参数,可以接收所有子类对象,体现多态的扩展性与便利。
弊端:
- 不能调用子类的特有功能
//假设有三个类,其中animal类是Dog类和Cat类的父类
//进行类的转换
animal a = new Dog;
if(a instanceof Dog){
Dog b = (Dog)a;
b.lookhome();
}else if (a instanceof Cat c){
Cat c = (Cat)a;
c.catmouse();
}else{
System.out.println("没有这个类型,无法转换")
}
//JDK14之后的新特性
if(a instanceof Dog b){
b.lookhome();
}else if (a instanceof Cat c){
c.catmouse();
}else{
System.out.println("没有这个类型,无法转换")
}
1.13、多态的综合练习
package entends.Polymorphism02;
public class Text {
public static void main(String[] args) {
Dog b = new Dog(2,"黑色");
Cat c = new Cat(2,"白色");
Person p = new Person("老王",40);
p.keepPet(b,"骨头");
p.keepPet(c,"小鱼干");
}
}
package entends.Polymorphism02;
public class animal {
private int age;
private String color;
public animal() {
}
public animal(int age, String color) {
this.age = age;
this.color = color;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public void eat(String somthing){
System.out.println("正在吃东西");
}
}
package entends.Polymorphism02;
public class Dog extends animal {
public Dog(int age,String color){
super(age,color);
}
@Override
public void eat(String somthing){
System.out.println(getAge()+"岁的"+getColor()+"的狗正在抱着"+somthing+"吃");
}
public void lookHome(){
System.out.println("狗正在看家");
}
}
package entends.Polymorphism02;
public class Cat extends animal{
public Cat(int age,String color){
super(age,color);
}
@Override
public void eat(String somthing){
System.out.println(getAge()+"岁的"+getColor()+"的猫正在抱着"+somthing+"吃");
}
public void catchMouse(){
System.out.println("猫正在抓老鼠");
}
}
package entends.Polymorphism02;
public class Person {
private String name;
private int age;
public Person() {
}
public void keepPet(animal a,String something){
if(a instanceof Dog b){
System.out.println(getAge()+"岁的"+getName()+"正在用"+something+"喂养狗");
b.eat(something);
} else if (a instanceof Cat c) {
System.out.println(getAge()+"岁的"+getName()+"正在用"+something+"喂养猫");
c.eat(something);
}
}
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;
}
}
1.14、包和final
包就是文件夹。用来管理各种不同功能的Java类,方便后期代码维护。
- 包名的规则:公司域名反写+包的作用,需要全部英文小写,见名知意。
包名+类名 被称为:全类名或者全限定名
使用其他类的规则
- 使用同一个包中的类时,不需要导包。
- 使用java.lang包中的类时,不需要导包。
- 其他情况都需要导包
- 如果同时使用两个包中的同名类,需要用全类名。
final
- 用final修饰一个方法:表明该方法是最终方法,不能被重写
- 用final修饰一个类:表明该类是最终类,不能被继承
- 用final修饰一个变量:叫做常量,只能被赋值一次
常量
实际开发中,常量一般作为系统的配置信息,方便维护,提高可读性。常量的命名规范:
- 单个单词:全部大写
- 多个单词:全部大写,单词之间用下划线隔开
细节:
- final修饰的变量是基本类型:那么变量存储的数据值不能发生改变
- final修饰的变量是引用类型:那么变量存储的地址值不能发生改变,对象内部的可以改变。
- 常量记录的数据是不能改变的
1.15、权限修饰符
- 权限修饰符:是用来控制一个成员能够被访问的范围的。
- 可以修饰成员变量,方法,构造方法,内部类。
实际开发中,一般只用private和public
- 成员变量私有
- 方法公开
特例:如果方法中的代码是抽取其他方法中共性代码,这个方法一般也私有。
1.16、代码块
- 局部代码块
- 写在括号里面的代码块
- 构造代码块
- 作用:可以把多个构造方法中重复的代码抽取出来
- 执行时机:我们在创建本类对象的时候会先执行构造代码块在执行代码块
- 写在成员位置中,把带参构造以及无参构造的函数里面相同的代码抽取出来,放在代码块(括号),就是构造代码块
- 静态代码块
- 格式
static{}
- 特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发、只执行一次
- 使用场景:在类加载的时候,做一些数据初始化的时候使用
- 格式
1.17、抽象类和抽象方法
- 抽象方法:将共性的行为(方法)抽取到父类之后。由于每一个子类执行的内容是不一样,所以,在父类中不能确定具体的方法体。该方法就可以定义为抽象方法。
- 抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类。
抽象类和抽象方法的定义格式
- 抽象方法的定义格式:
public abstract 返回值类型 方法名(参数列表)
; - 抽象类的定义格式:
public abstract class 类名{}
;
抽象类和抽象方法到的注意事项
- 抽象类不能实例化
- 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
- 可以有构造方法
- 抽象类的子类
- 要么重写抽象类中的所有抽象方法
- 要么是抽象类
package abstract_.A0dome1;
public abstract class animal {
private String name;
private int age;
public animal() {
}
public animal(String name, int age) {
this.name = name;
this.age = age;
}
public void drink(){};
public abstract void eat();
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "animal{name = " + name + ", age = " + age + "}";
}
}
package abstract_.A0dome1;
public class Dog extends animal {
public Dog(String name,int age) {
super(name,age);
}
@Override
public void eat() {
System.out.println("吃骨头");
}
}
package abstract_.A0dome1;
public class frog extends animal{
public frog(String name,int age) {
super(name,age);
}
@Override
public void eat() {
System.out.println("吃虫子");
}
}
package abstract_.A0dome1;
public class sheep extends animal{
public sheep(String name,int age) {
super(name,age);
}
@Override
public void eat() {
System.out.println("吃草");
}
}
package abstract_.A0dome1;
public class Text {
public static void main(String[] args) {
Dog d = new Dog("quiqui",2);
frog f = new frog("xiao",2);
sheep s = new sheep("meiyangyang",3);
d.eat();
f.eat();
s.eat();
}
}
1.18、接口
接口的定义和使用
- 接口用关键字interface来定义
public interface接口名{}
; - 接口不能实例化
- 接口和类之间是实现关系,通过implements关键字表示
public class类名implements接口名l - 接口的子类(实现类)
要么重写接口中的所有抽象方法
要么是抽象类
注意1:接口和类的实现关系,可以单实现,也可以多实现。
public class 类名 implements接口名1,接口名2{}
;
注意2:实现类还可以在继承一个类的同时实现多个接口。
public class 类名 extends 父类 implements接口名1,接口名2{}
;
package interface_.aDome1;
public abstract class animal {
private String name;
private int age;
public animal() {
}
public animal(String name, int age) {
this.name = name;
this.age = age;
}
public abstract void eat();
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "animal{name = " + name + ", age = " + age + "}";
}
}
package interface_.aDome1;
public class dog extends animal implements swim{
public dog(){};
public dog(String name ,int age){
super();
}
@Override
public void eat() {
System.out.println("狗吃骨头");
}
@Override
public void swim() {
System.out.println("狗刨");
}
}
package interface_.aDome1;
public class forg extends animal implements swim{
public forg(){};
public forg(String name ,int age){
super(name,age);
}
@Override
public void eat() {
System.out.println("青蛙吃虫子");
}
@Override
public void swim() {
System.out.println("蛙泳");
}
}
package interface_.aDome1;
public class rabbit extends animal{
public rabbit(){};
public rabbit(String name ,int age){
super();
}
@Override
public void eat() {
System.out.println("兔子吃胡萝卜");
}
}
package interface_.aDome1;
public interface swim {
void eat();
public abstract void swim();
}
package interface_.aDome1;
public class Text {
public static void main(String[] args) {
dog g = new dog("quiqui",2);
forg f =new forg("qiongwa",2);
rabbit r = new rabbit("tuzxi",3);
g.eat();
g.swim();
f.eat();
f.swim();
r.eat();
}
}
1.19、接口的细节
接口中成员的特点
- 成员变量
- 只能是常量
- 默认修饰符:
public
static final
- 构造方法
- 没有
- 成员方法
- 只能是抽象方法
- 默认修饰符:public abstract
- JDK7以前:接口中只能定义抽象方法。
- JDK8的新特性:接口中可以定义有方法体的方法。
- JDK9的新特性:接口中可以定义私有方法。
接口和类之间的关系
- 类跟类的关系
- 继承关系,只能单继承,不能多继承,但是可以多层继承
- 类和接口的关系
- 实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
- 接口和接口的关系
- 继承关系,可以单继承,也可以多继承
1.19、练习-编写带有接口和抽象类的标准JavaBean类
package interface_.aDome2;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Person{name = " + name + ", age = " + age + "}";
}
}
package interface_.aDome2;
public abstract class Player extends Person {
public Player(){};
public Player(String name,int age){
super(name,age);
};
public abstract void study();
}
package interface_.aDome2;
public abstract class trainer extends Person {
public trainer(){};
public trainer(String name,int age){
super(name,age);
};
public abstract void teaching();
}
package interface_.aDome2;
public interface english {
public abstract void sayenglish();
}
package interface_.aDome2;
public class basketballplay extends Player{
public basketballplay(){};
public basketballplay(String name,int age){
super(name,age);
};
@Override
public void study() {
System.out.println("学篮球");
}
}
package interface_.aDome2;
public class basketballtariner extends trainer {
public basketballtariner(){};
public basketballtariner(String name,int age){
super(name,age);
};
@Override
public void teaching() {
System.out.println("学篮球");
}
}
package interface_.aDome2;
public class pingpangplayer extends Player implements english{
public pingpangplayer(){};
public pingpangplayer(String name,int age){
super(name,age);
};
@Override
public void study() {
System.out.println("学乒乓球");
}
@Override
public void sayenglish() {
System.out.println("说英语");
}
}
package interface_.aDome2;
public class pingpangtrainer extends Player implements english{
public pingpangtrainer(){};
public pingpangtrainer(String name, int age) {
super(name,age);
}
@Override
public void study() {
System.out.println("教乒乓球");
}
@Override
public void sayenglish() {
System.out.println("说英语");
}
}