面向对象
什么是对象? 什么是类?
对象:软件中真是存在的单个的个体/东西
类: 代表一类个体; 类是对象的模子,对象是类的具体的实例, 可以将类理解为 类别/模子/图纸
类中可以包含:
对象的属性/特征/数据-----------成员变量
对象的行为/动作/功能-----------方法
一个类可以创建多个对象
关键字
this: 指代当前对象(即指代调用者), 哪个对象调方法它指的就是哪个对象
只能用在方法的里面, 方法中访问成员变量之前默认有一个this.
this的用法:
this.成员变量名----------------------------------访问成员变量(经常用)
当成员变量与局部变量同名时, 若想访问成员变量, 则不能省略this. ;否则以就近原则访问
this.方法名()--------------------------------------调用方法(一般不用)
this()------------------------------------------------调用构造方法(一般不用)
super: 指代当前对象的超类对象
super.成员变量名----------------------访问超类的成员变量
当超类成员变量和派生类成员变量同名时,super指超类的, this指派生类的
若没有同名现象,写super和this是一样的
构造方法: 空参构造/有参构造
作用: 给成员变量赋值初始化
语法:与类同名, 没有返回值类型(连void都没有)
调用:在创建(new)对象时被自动调用
若自己不写构造方法,则编译器默认提供一个无参构造方法,若自己写了构造方法,则不再默认提供
构造方法可以重载, 即空参/有参构造
public class Car {
String brand; //品牌
String color; //颜色
double price; //价格
Car(){
}
Car(String brand,String color,double price){
this.brand=brand;
this.color=color;
this.price=price;
}
}
继承:
作用: 复用代码
通过extends 实现继承
超类/父类: 共有的属性和行为
派生类/子类:特有的属性和行为
派生类可以访问:超类的+派生类的, 超类不能访问派生类的
一个超类可以有多个派生类,一个派生类只能有一个超类------单一继承
具有传递性
class Aoo{}
class Boo extends Aoo{}
class Coo extends Boo{}
java规定:构造派生类之前必须先构造超类
在派生类的构造方法中若没有调用超类的构造方法,则默认super()调用超类的无参构造方法
在派生类的构造方法中若自己调用了超类的构造方法,则不再默认提供
注意: super()调用超类构造方法, 必须位于派生类构造方法中的第一行
public class Person {
String name;
int age;
String address;
Person(String name,int age,String address){
this.name=name;
this.age=age;
this.address=address;
}
void sayHi(){
System.out.println("大家好,我叫"+name+",今年"+age+"岁了,家
住"+address);
}
}
public class Student extends Person{
StringclassName;
Student(Stringname,intage,Stringaddress,StringclassName){
super(name,age,address); //传递的是name/age/address的值
this.className=className;
//super(name,age,address);// 错误编译, 必须放在第一位
}
voidstudy(){
System.out.println(name+"正在学习...");
}
}
继承的是超类的成员变量和普通方法,不包括超类的构造方法,超类的构造方法是被派生类通过super()来调用的,而不是继承的
class Aoo{
int a;
Aoo (){
}
void show(){
}
}
class Boo extends Aoo{
继承了Aoo类的a+show(),并没有继承Aoo类的构造方法
}
抽象类, 抽象方法 : 均由abstract 修饰
抽象方法: 只有方法的定义,没有具体的实现 (没有方法体), 连{}都没有
抽象类:
包含抽象方法的类必须是抽象类, 但不包含抽象方法的类也可以声明为抽象类
抽象类不能被实例化(new对象)
抽象类是需要被继承的, 派生类:
必须重写抽象类中的所有抽象方法--------------变不完整为完整
抽象类的意义:
封装共有的属性和行为-----------------------代码复用
可以包含抽象方法, 目的是为所有派生类统一入口(方法名字统一), 强制必须重写
public abstract class Animal {
String name;
int age;
Animal(String name,int age){
this.name=name;
this.age=age;
}
abstract void eat();//抽象方法
}
public class Dog extends Animal{
Dog(String name,int age){
super(name,age);
}
void eat(){//重写的抽象方法
System.out.println(color+"色的"+age+"岁的狗狗"+name+"正在吃肯
头...");
}
}
接口: 由 interface 定义
是一种引用数据类型
只能包含抽象方法(常量 、默认方法、静态方法、私有方法)
不能被实例化
接口是需要被实现/继承的, 实现类/ 派生类: 必须重写接口中所有的抽象方法
注意: 重写接口中的方法时,必须加 public
interface Inter{
public abstract void show(); //完整的写法
void show();
// void show (){} 编译错误, 抽象方法不能有方法体
}
class Aoo implements Inter {
public void show () {}
}
public class InterfaceDemo {
public static void main(String[] args) {
//Inter o = new Inter(); //编译错误,接口不能被实例化
}
}
一个类可以实现多个接口, 用逗号分隔. 若又继承又实现时, 应先继承后实现
接口可以继承接口
引用类型数组: ----------与基本类型数组的区别
区别1: 给引用类型数组的元素赋值时, 需要new个对象
区别2: 访问引用类型数组的元素的属性/行为时, 需要打点访
多态:多种形态
向上造型/自动类型转换:
超类型的引用指向派生类的对象
父类 引用 = new 子类();
能点出来什么, 看引用的类型
编译看左边, 执行看右边
编译时看父类中是否有该方法,如果有, 执行时直接去子类找到该重写的方法
向下转型/强转类型转换, 成功的条件只有两种:
引用所指向的对象, 就是该类型
引用所指向的对象, 实现了该接口或继承了该类
强转时,如果类型不同,会报ClassCastException类型转换异常
因此在强转之前可以先通过 instanceof 来判断引用的对象是否是该类型
注意: instanceof 返回boolean结果, 为true 即为强转成功
若想访问的属性/行为在超类中没有,则需要强制类型转换
成员内部类
若A类(Baby)只让B类(Mama)用,并且A类(Baby)还想访问B类(Mama)的成员时,可以设计成员内部类
class Mama{ //外部类
String name;
void create(){
Baby b =new Baby(); //内部类对象通常在外部类中创建
}
class Baby{ //内部类
void show(){
System.out.println(name); //简写
System.out.println(Mama.this.name); //完整写法,Mama.this指外部类对象
//System.out.println(this.name); //编译错误,this指当前Baby对象
}
}
}
匿名内部类: 简化代码
若想创建一个派生类的对象,并且对象只创建一次, 可以设计为匿名内部类
注意:匿名内部类中不能修改外面的局部变量的值
问: 内部类有独立的.class文件吗?
答: 有
public class TimerDemo {
public static void main(String[] args) {
//想要创建一个派生类的对象,并且这个对象只用一次,可以设计为匿名内部类
/**
匿名内部类:
例如:new TimerTask() {
@Override
public void run() {System.out.println("起床了,懒鬼...");}
}
1.实现了接口或继承了类 {@Override public void run() {System.out.println("起床了,懒鬼...");} } 这个匿名类 继承了 TimerTask这个类
2.创建了对象 new 关键字创建了这个对象
3.重写了方法{@Override
public void run() {System.out.println("起床了,懒鬼...");}
}
*/
Timer timer = new Timer();
int interval=5000;
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("起床了,懒鬼...");
}
},interval,1000);
}
}
package和import
package: 声明包------避免类的命名冲突-----------包名所有字母都小写
同包中的类不能同名,但不同包中的类可以同名
类的全称: 包名.类名 包名常常有层次结构
import: 导入类
同包中的类可以直接访问, 但是不同包中的类不能直接访问, 若想访问:
先import导入类,在访问类----------建议
类的全称---------------------------太繁琐
本节相关案例代码
//父类 动物类
public abstract class Animal {
String name;
int age ;
String color;
Animal(String name, int age , String color){
this.name =name;
this.age=age;
this.color=color;
}
void drink(){
System.out.println("名字为:"+name+",颜色为:"+color+"的它正在喝水...." +"它今年"+age+"岁了");
}
abstract void eat ();
}
//接口
public interface Swim {
void swim();
}
//子类 狗类
public class Dog extends Animal implements Swim{
String type;
Dog(String name,int age , String color , String type){
super(name,age,color);
this.type=type;
}
void eat(){
System.out.println("名字为:"+name+",颜色为:"+color+"的"+type+"它正在吃骨头...." +"它今年"+age+"岁了");
}
public void swim(){
System.out.println("名字为:"+name+",颜色为:"+color+"的"+type+"它正在练习狗刨...." +"它今年"+age+"岁了");
}
void lookHemo(){
System.out.println("名字为:"+name+",颜色为:"+color+"的"+type+"它正在看家...." +"它今年"+age+"岁了");
}
}
//子类 鱼类
public class Fish extends Animal implements Swim{
String tpye ;
Fish(String name,int age , String color , String type){
super(name, age, color);
this.tpye=type;
}
@Override
void eat() {
System.out.println("名字为:"+name+",颜色为:"+color+"的"+tpye+"它正在吃小虾米...." +"它今年"+age+"岁了");
}
@Override
public void swim() {
System.out.println("名字为:"+name+",颜色为:"+color+"的"+tpye+"它正在溪水...." +"它今年"+age+"岁了");
}
}
//子类 鸡类
public class Chick extends Animal {
String tpye;
Chick(String name, int age, String color, String type) {
super(name, age, color);
this.tpye = type;
}
@Override
void eat() {
System.out.println("名字为:" + name + ",颜色为:" + color + "的" + tpye + "它正在吃小米粒...." +"它今年" + age + "岁了");
}
void layEggs(){
System.out.println("名字为:"+name+",颜色为:"+color+"的"+tpye+"它正在下蛋...." +"它今年"+age+"岁了");
}
}
//多态演示
public class Master {
void feed(Animal animals){
animals.eat();
animals.drink();
}
}
//测试类
public class Test {
public static void main(String[] args) {
//1.将不同对象(狗,鱼,鸡)统一封装到一个数组(动物数组)中来访问,实现代码的复用
Animal[]animals=new Animal[3];
animals[0]=new Dog("巧克力",2,"黑白","狗狗");
animals[1]=new Fish("棒棒糖",1,"彩色","鱼");
animals[2]=new Chick("玉米棒",3,"黄色","小鸡");
for (int i = 0; i < animals.length; i++) {
//多态 编译看左边,运行看右边
System.out.println(animals[i].name);
animals[i].eat();
animals[i].drink();
//如果超类想访问子类的方法,需要进行类型转换
//在转换时为了保证转换的类型相同, 可以用 instanceof 进行判断是否是同一类型
if (animals[i] instanceof Dog){
Dog dog= (Dog) animals[i];
dog.lookHemo();
}
if (animals[i] instanceof Chick){
Chick chick = (Chick) animals[i];
chick.layEggs();
}
if (animals[i] instanceof Swim s) {
s.swim();
}
}
System.out.println("--------------------------------------------------");
//2.把超类型作为参数或返回值类型,传递或返回派生类(Dog/Fish/Chick)对象,以扩大方法的应用范围(所有Animal)
Master master =new Master();
Dog dog =new Dog("大米",2,"白色","狗狗");
Fish fish =new Fish("小米",1,"黄色","鱼");
Chick chick =new Chick("白面",2,"黄色","小鸡");
master.feed(dog);
master.feed(fish);
master.feed(chick);
}
}
补充
方法的重载与重写
重载:发生在同一类中,方法名相同,方法的参数不同(类型,顺序)
void show ()//无参
void show (String name ,int age) void show (int age , String name) //有参顺序不同
重写:发生在不同类中(继承或者实现)父子类,方法名相同,参数相同
*重写的方法被调用时,看对象的类型------------------new谁就调谁的,这是规定*
abstract calss Fu (){ abstract void eat() }
class Zi extends Fu(){ void eat(){System.out.println("吃饭")}
重载和重写的特殊情况
class Aoo{
void show(){}
}
class Boo extends Aoo{ //此类中发生了show方法的重载
void show(String name){}
}
class Boo{ //既没有重载也没有重写
void show(){}
}
class Boo{ //既没有重载也没有重写
void show(String name){}
}
class Boo extends Aoo{ //发生重写了
void show(){}
}
类间关系:
类和类-------------------------------继承
接口和接口-------------------------继承
类和接口----------------------------实现
null:表示空,没有指向任何对象。
若引用的值为null,则该引用不能再进行任何操作了,若操作则发生NullPointerException空指针异常。
隐式的引用:
this:指代当前对象
super:指代当前对象的超类对象
外部类名.this:指代当前对象的外部类对象