目录
封装:
使用private关键字将属性封装(这个属性只在当前类的内部可见,对外部隐藏)
方法的重载:
在同一个类中,定义了若干方法名称相同,参数列表不同,返回值无关的一组方法
继承:
当类和类之间满足一个类 is a 另外一个类一定是存在继承关系.
Bird is an Animal
Duck is an Animal
此时Bird和Duck都是Animal的子类
当一个类继承了另外一个类,另一个类中所有的属性和方法子类就天然具备了.
Java中使用extends表示类的继承
public class Dog extends Animal
满足继承关系的类之间一定是逻辑垂直的关系
继承规则:
a. 要使用继承,必须要满足is a的关系
b. 一个子类只能继承一个父类(单继承)
c.子类会继承父类所有属性和方法,显示继承(public属性和方法可以直接使用)
隐式继承(private属性和方法),子类也继承了这个属性和方法,但无法直接使用(父类提供的 get/set方法).
protected:
protected权限:当前类的内部/同包不同类/子类中可以使用
private<default<protected<public
super:
修饰属性:表示直接从父类中寻找同名属性
修饰方法:表示直接从父类中寻找同名方法
public class B {
public B() {
System.out.println("1.B的构造方法");
}
{
System.out.println("2.B的构造代码快");
}
static {
System.out.println("3.B的静态快");
}
}
public class D extends B{
public D() {
System.out.println("4.D的构造方法");
}
{
System.out.println("5.D的构造快");
}
static {
System.out.println("6.D的静态快");
}
public static void main(String[] args) {
System.out.println("7.main开始");
new D();
new D();
System.out.println("8.main结束");
}
}
当 new D(); 无参构造产生子类对象之前先默认调用父类的构造方法,产生父类对象,然后才会 执行子类的构造方法
要产生一个子类对象先默认产生父类对象!!!
结果:
3.B的静态快
6.D的静态快
7.main开始
2.B的构造代码快
1.B的构造方法
5.D的构造快
4.D的构造方法
2.B的构造代码快
1.B的构造方法
5.D的构造快
4.D的构造方法
8.main结束
System.out.println(this.name); //直接当前类中寻找同名属性,若不存在,在向上找 System.out.println(super.name);//直接从父类中寻找同名属性,若不存在,在向上找父类中定义了private name;就无权访问
super修饰构造方法:
public class Animal {
public String name;
//Animal默认的无参构造就不再产生
public Animal(String name) {
this.name = name;
}
}
public class Dog extends Animal{
//显示调用父类的有参构造
//要想产生父类的对象就要调用父类的构造方法
public Dog() {
super("name");
}
public static void main(String[] args) {
new Dog();
}
}
super(); //直接父类的无参构造,可写可以不写
若父类中不存在无参构造,则子类构造方法的首行必须使用super(有参构造)
在一个构造方法中无法显示使用this()和super()同时出现
Final:
修饰属性:表示属性值不能修改,常量
修饰类表示这个类无法继承
多态:
一个引用可以表现出多种行为/特征
向上转型:最大的意义在于参数统一化,降低使用者的使用难度!!
父类名称 父类引用 = new 子类对象();
Animal animal = new Dog();
向上转型发生在有继承关系的类之间
不一定时之间子类,也可以是孙子类
最主要的多态:继承+方法重写!!!
//有了向上转型之后最顶端的父类引用就可以指代所有的子类对象
//当Animal有新的子类时,就非常容易扩展
fun(new Dog());
fun(new Duck());
//fun中animal局部变量的引用调用eat方法时,当传入不同的对象,表现出来不同的eat,
这就是多态
public static void fun(Animal animal){
animal.eat();
}
override:
方法的重写(override):发生在有继承的类之间,子类定义了和父类除权限不同,其他全都相同的 方法(返回值可以是向上转型的返回值) ,这一组方法称为方法的重写
Animal animal1 = new Dog();
Animal animal2 = new Duck();
Animal animal3 = new Bird();
fun(animal1);
fun(animal2);
fun(animal3);
public static void fun(Animal animal){
animal.eat();
}
这三个类都重写了eat方法 ,到底调用了谁的方法哪?
答: 看new的是谁调用的就是谁的eat方法.
若子类没有重写这个方法,则就近匹配规则,谁近就调用谁的
当发生重写时,子类的权限要>=父类权限
父类方法使用private,子类方法使用public是否可以?
答:不可以,private不包含在内
java中有一个@override
使用这个注解在重写方法之前,帮助校验重写方法是否符合规则
能否重写staitic方法?
答:不能, 多态的本质就是调用了不同的子类对象,使这些子类对象所属的类覆写相应的方法
才能表现出不同的行为,static和对象无关!!!
向上转型的应用:
1.方法传参使用最多
2.方法的返回值
pulic static Animal test(){
Dog dog = new Dog();
return dog;
}
public class B {
public B() {
fun();
}
public void fun(){
System.out.println("b.fun");
}
}
public class D extends B{
private int num = 10;
//这时还没有执行D的构造方法!! D的所有属性都是默认值
public void fun(){
System.out.println("D.fun,num = "+ num);
}
//调用D的无参构造,这时存在继承,优先调用B的构造方法产生父类对象
public static void main(String[] args) {
D d = new D();
}
}
结果:D.fun,num = 0
向下转型:
当要使用子类中独有的属性和方法时就要向下转型!
类名称 引用名称 = new 类实例();
引用名称.方法名称();
能通过"."访问的方法,类名称说了算
能访问的方法必须在类中定义过,编译器会先在类中查找是否包含此方法
至于这个方法表现出来是哪个类的样子,实例所在方法说了算
public class Animal {
public void eat(){
System.out.println("Animal的eat方法");
}
}
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("Dog类的eat方法");
}
public void play(){
System.out.println("Dog类独有的play方法");
}
}
public static void main(String[] args) {
//要发生向下转型,首先要向上转型
Animal animal = new Dog();
animal.eat();
//要想使用Dog类中独有的play方法,就要向下转型
Dog dog = (Dog) animal;
dog.play();
}
//毫无关系的两个类之间无法强转
Animal animal = new Animal();
Dog dog = (Dog)Animal;//error
//此时这个animal2引用和Dog类毫无关系
Animal animal2 = new Animal();
//要发生向下转型首先父类引用就是通过该类向上转型产生的
Dog dog2 = (Dog) animal2;
dog2.play();
instanceof:
向下转型时会有风险,类型转换异常!!
引用名称 instanceof 类 => 返回布尔值,表示该引用指向的本质不是该类对象
Animal animal1 = new Animal();
Animal animal2 = new Dog();
if(animal1 instanceof Dog){
Dog dog = (Dog) animal1;
System.out.println("animal1"+"转型成功");
}else {
System.out.println("animal1转型失败");
}
if (animal2 instanceof Dog){
Dog dog = (Dog) animal2;
System.out.println("animal2"+"转型成功");
}else {
System.out.println("animal2"+"转型失败");
}
结果: animal1转型失败
animal2转型成功
public class Person {
public void fun(){
this.test(); //表示此时在父类中
}
//test方法是private权限子类无法覆写
private void test() {
System.out.println("1.Person的test方法");
}
}
public class Student extends Person{
//子类并没有覆写父类方法,就是一个普通方法
public void test(){
System.out.println("2.Student的test方法");
}
}
public class Test01 {
public static void main(String[] args) {
new Student().fun();
}
}
Person test() {
System.out.println("1.Person的test方法");
return new person();
}
//子类使用student作为返回值,父类使用Person作为返回值是可以的,Student is a Person
public Student test(){
System.out.println("2.Student的test方法");
return new Student();
}
抽象类:
抽象类,只是比普通类多了一些抽象方法.
抽象类虽然没法直接实例化对象,但依然要满足 is a 原则!!!
Java中定义抽象类或者抽象方法使用abstract关键字
1.抽象方法所在的类必须使用abstract声明为抽象类
抽象方法:使用abstract关键字声明,没有方法体的方法,称为抽象方法
//抽象方法所在的类,必须为抽象类
public abstract class Sharp {
//抽象方法没有方法体,到子类实现
public abstract void print();
}
Java中,没有方法体的方法就是抽象方法?
答:error. 本地方法也没有方法体,不是抽象方法
本地方法,不是抽象方法,这个方法的具体实现由JVM实现JVM是C++写的
本地方法指的是调用了C++中的同名方法
2.抽象类,不能实例化对象,哪怕类中一个抽象方法没有
只能通过子类向上转型为抽象父类
public abstract class Sharp {
public abstract void print();
}
public class Cycle extends Sharp{
@Override
public void print() {
System.out.println("haha");
}
public static void main(String[] args) {
Sharp sharp = new Cycle();
sharp.print();
}
}
3.子类继承了抽象类,子类就必须覆写抽象父类中的所有抽象方法(子类是普通类),只能单继承
4. 抽象类不能实例化对象,但是也存在构造方法,子类在实例化时,仍然遵从继承的规则,先调用父类的构造方法,然后调用子类的构造方法!!!
abstract class BaseTest {
public BaseTest() {
this.print();
}
abstract void print();
}
class Fun extends BaseTest {
private int num = 10;
@Override
void print() {
System.out.println("num = "+num);
}
public static void main(String[] args) {
new Fun();
}
}
结果: num = 0
当一个类既可以使用抽象类也可以使用接口,优先使用接口!!!
接口:
接口使用的两种场景:
1.接口表示具有某种能力/行为,子类实现接口时不是 is a 而是具备这种行为或能力(多实现)
"游泳" ->person满足,Dog也满足,Duck也满足
2.接口表示一种规范或标准
"USB接口",5G标准
接口中只有全局常量和抽象方法
接口使用关键字interface声明接口,子类使用implements实现接口
//USB接口表示一种规范
public interface USB {
//插入
void plugIn();
//工作
void work();
}
Mouse和Keyboard都属于USB的子类
//子类实现接口必须覆写所有抽象方法
public class Mouse implements USB{
@Override
public void plugIn() {
System.out.println("鼠标驱动加载中");
}
@Override
public void work() {
System.out.println("鼠标正在工作中");
}
}
public class KeyBoard implements USB{
@Override
public void plugIn() {
System.out.println("键盘驱动安装中~~");
}
@Override
public void work() {
System.out.println("键盘工作中~~");
}
}
只要这个设备满足USB接口,都可以插入到电脑识别,兼容所有的USB子类对象.
fun(Mouse mouse) 这个接口只能插入鼠标,键盘都不可以,这两个类毫无关系
public class Computer {
public static void main(String[] args) {
Computer computer = new Computer();
KeyBoard keyBoard = new KeyBoard();
Mouse mouse = new Mouse();
computer.fun(keyBoard);
computer.fun(mouse);
}
public void fun(USB usb){
usb.plugIn();
usb.work();
}
}
//子类可以实现多个父接口,父接口里的抽象方法都要覆写
public class KeyBoard implements USB,IRun{
@Override
public void plugIn() {
System.out.println("键盘驱动安装中~~");
}
@Override
public void work() {
System.out.println("键盘工作中~~");
}
}
接口中只有全局常量和抽象方法,因此接口中 public abstract 可以省略
只保留最核心的返回值,参数列表和方法名即可
public interface USB {
//插入
void plugIn();
//工作
void work();
}