类是模板,规划了对象应该拥有怎样的属性和方法
public class A{
//-------------属性------------------
//成员属性/实例属性
String str1;
int i1;
//静态属性/类属性
static String str2;
static String i2;
//-------------方法------------------
/**
*成员方法/实例方法:
* 访问修饰符 返回值类型 方法名(参数列表){
* ...代码块...
* }
*/
public void method01(){
}
public void method02(){
}
/**
*静态方法/类方法:
* 访问修饰符 static 返回值类型 方法名(参数列表){
* ...代码块...
* }
*/
public static void method03(){
}
public static void method04(){
}
}
对象是类的具体表现形式,可以操作对象中的各种信息
比如:操作属性、方法
public class Test {
public static void main(String[] args) {
//创建Perosn类的对象
Person p = new Person();
//设置属性
p.name = "吴彦祖";
p.age = 18;
//获取属性
String n = p.name;
System.out.println(n);
System.out.println(p.age);
//调用方法
p.eat();
p.sleep();
}
}
//人类
class Person{
String name;
int age;
public void eat(){
System.out.println("吃饭饭");
}
public void sleep(){
System.out.println("吃饭饭");
}
}
依据具体参数类型匹配到对应方法
- 在同一个类中
- 方法名相同
- 形参列表的个数或者类型不同
- 与返回值无关
public class Test {
public static void main(String[] args) {
Operation operation = new Operation();
//根究参数类型自动匹配对应add方法
int result = operation.add(10, 20);
System.out.println(result);
}
}
//运算类
class Operation{
//2个int类型做加法
public int add(int num1,int num2){
return num1 + num2;
}
//3个int类型做加法
public int add(int num1,int num2,int num3){
return num1 + num2 + num3;
}
}
在一个类中,多个方法功能一样,所以方法名应该相同,根据传入的不同类型,系统自动匹配到对应的方法,这样减少了因取名字带来的困扰,更使得类的可读性大幅度提高
成员变量:
必须用对象调用
对象被GC会收回后,成员变量也会被回收
作用域在整个对象中
创建对象时,系统赋给默认值
整数类型:0
浮点类型:0.0
字符类型:’ ’
布尔类型:flase
引用类型:null
局部变量(方法里的变量):
- 方法被调用后,方法中的变量会被GC立刻回收掉
- 作用域在方法中
- 局部变量没有初始值
成员方法:必须用对象调用
静态方法:可以用对象或者类名调用,建议使用类名直接调用,因为静态方法属于类方法
与类名相同且没有返回项的方法
作用:创建对象
注意:如果该类没有任何构造方法,系统会默认实现无参构造(没有参数的构造方法)
public class Test {
public static void main(String[] args) {
//创建Perosn类的对象
Person p1 = new Person();
Person p2 = new Person("吴彦祖",18);
System.out.println(p1.name + " -- " + p1.age);
System.out.println(p2.name + " -- " + p2.age);
}
}
//人类
class Person{
String name;
int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
无参构造可以创建对象,但是有参构造不仅可以创建对象还可以在创建对象时给属性赋值
private - 私有化
作用:
修饰属性:私有化属性,该属性不能在本类以外直接调用
修饰方法:私有化方法,该方法不能在本类以外直接调用
public class Test {
public static void main(String[] args) {
Person p = new Person();
System.out.println(p.name + " -- " + p.age);//这里会报错
p.method01();//这里会报错
}
}
//人类
class Person{
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private void method01(){
System.out.println("Person类私有化方法");
}
}
让属性和方法更加安全,因为不能让类的外部调用
如果不想属性和方法让外界调用,就private修饰
private+get/set方法,类里提供公有化的方法让外界可以获得对象中私有化的属性和方法
很多人不理解既然私有化的属性和方法,为什么还要设置公有化的方法让外界有权限去调用?
因为如果直接访问属性,程序无法记录属性何时被调用或者说被谁给调用,而公有化方法中可以做相应的记录,详情请看"具体使用"
public class Test {
public static void main(String[] args) {
Person p = new Person();
p.setName("吴彦祖");
p.setAge(18);
System.out.println(p.getName() + " -- " + p.getAge());
p.method02();
}
}
//人类
class Person{
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
System.out.println("name属性被获取了");
return name;
}
public void setName(String name) {
System.out.println("name属性被设置了");
this.name = name;
}
public int getAge() {
System.out.println("age属性被获取了");
return age;
}
public void setAge(int age) {
System.out.println("age属性被设置了");
this.age = age;
}
private void method01(){
System.out.println("Person类私有化方法");
}
public void method02() {
System.out.println("调用Person类method01私有化方法");
method01();
}
}
this - 本对象
作用:
this.属性:调用本对象的属性
this.方法:调用本对象的方法
this():根据传参类型调用本对象的构造方法(此用法只能放在除了本构造方法的其他构造里)
public class Test1 {
public static void main(String[] args) {
Person p = new Person("吴彦祖",18,'男');
p.method02();
}
}
//人类
class Person{
private String name;
private int age;
private char sex;
public Person() {
}
public Person(String name, int age) {
this.name = name;//调用本对象的属性
this.age = age;//调用本对象的属性
}
public Person(String name, int age, char sex) {
this(name,age);//调用本类其他的构造方法
this.sex = sex;
}
public void method01(){
System.out.println("method方法");
}
public void method02() {
//注意:当本方法中没有相同名字的局部变量时,可以直接被this忽略掉
///this.method01()
//System.out.println(this.name + " -- " + this.age);
method01();//调用本对象的方法
System.out.println(name + " -- " + age + " -- " + sex);//调用本对象的属性
}
}
static - 私有的
作用:
修饰属性:类属性/类变量/静态变量/静态属性,直接用类名调用
应用场景:状态码(静态常量),后续会碰到
修饰方法:类方法/静态方法,直接用类名调
应用场景:工具类,只需要使用类里的具体功能,那就把类视作工具类,类里的方法都是静态方法, 直接用类名调用即可
静态代码块:初始化数据
应用场景:初始化该类的静态属性
public class Test {
public static void main(String[] args) {
MyClass m1 = new MyClass();
MyClass m2 = new MyClass();
m1.str1 = "成员属性1";
m2.str1 = "成员属性2";
System.out.println(m1.str1);
System.out.println(m2.str1);
//静态属性是该类所有对象共享的,是类属性,所以应该用类名调用
// m1.str2 = "静态属性1";
// m2.str2 = "静态属性2";
// System.out.println(m1.str2);
// System.out.println(m2.str2);
m1.str2 = "静态属性2";
System.out.println(MyClass.str2);
}
}
class MyClass{
String str1;
static String str2;
}
public class Test {
public static void main(String[] args) {
int[] is = {
1,5,4,2,6};
int max = MyArrays.getMax(is);
System.out.println("获取数组中的最大值:" + max);
}
}
//自定义数组工具类
class MyArrays{
public static int getMax(int[] is) {
int max = is[0];
for (int i = 1; i < is.length; i++) {
if(max < is[i]){
max = is[i];
}
}
return max;
}
}
public class Test {
public static void main(String[] args) {
for (String name : NameContainer.names) {
System.out.println(name);
}
}
}
//姓名容器类
class NameContainer{
static String[] names = new String[10];
static{
//初始化静态属性的数据
names[0] = "吴彦祖";
names[1] = "彭于晏";
names[2] = "何翰宇";
}
}
public class Test {
public static void main(String[] args) {
//输出:静态代码块 -> 代码 -> 构造方法
MyClass m = new MyClass();
//输出:静态代码块 -> 静态等待
MyClass.method();
}
}
class MyClass{
String str1;
static String str2;
public MyClass() {
System.out.println("构造方法");
}
{
str1 = "aaa";
System.out.println("代码块 - " + str1);
}
static{
str2 = "bbb";
System.out.println("静态代码 - " + str2);
}
public static void method() {
System.out.println("静态方法");
}
}
代码块调用法则总结:
- 代码块可以初始化属性
- 静态代码块可以初始化静态属性
- 使用该类就会把类的字节码文件(.class文件)加载到方法区中,此时就会调用静态代码块
静态变量:类变量,该类的所有对象共享一份,(JDK1.7 - 存储在静态常量区中 ,JDK1.8 - 堆中)
成员变量:该变量每个对象独享一份,存储在堆内存的对象中
子类继承父类所有属性和方法
私有化属性和方法不能直接被调用,但是可以间接调用,见 “具体使用”
使用关键字extends继承:class 子类 extends 父类{}
public class Test {
public static void main(String[] args) {
Chinese c = new Chinese();
c.setChineseId("123..."); //操作子类的属性并调用子类的方法
c.setName("吴彦祖"); //操作父类的属性并调用父类的方法
c.setAge(18); //操作父类的属性并调用父类的方法
System.out.println(c.getChineseId());//操作子类的属性并调用子类的方法
System.out.println(c.getName()); //操作父类的属性并调用父类的方法
System.out.println(c.getAge()); //操作父类的属性并调用父类的方法
c.playTaiJi();//调用子类的方法
Japanese j = new Japanese();
j.setJapaneseId("xxx...");//操作子类的属性并调用子类的方法
j.setName("水菜丽"); //操作父类的属性并调用父类的方法
j.setAge(26); //操作父类的属性并调用父类的方法
System.out.println(j.getJapaneseId());//操作子类的属性并调用子类的方法
System.out.println(j.getName()); //操作父类的属性并调用父类的方法
System.out.println(j.getAge()); //操作父类的属性并调用父类的方法
j.playVideo();//调用子类的方法
}
}
//父类
class Person{
private String name;
private int age;
public Person() {
}
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;
}
}
//子类
class Chinese extends Person{
private String chineseId;//中国人的身份证(子类独有的属性)
//子类独有的方法
public Chinese() {
}
public Chinese(String chineseId) {
this.chineseId = chineseId;
}
public String getChineseId() {
return chineseId;
}
public void setChineseId(String chineseId) {
this.chineseId = chineseId;
}
public void playTaiJi(){
System.out.println("中国人:打太极");
}
}
//子类
class Japanese extends Person{
private String japaneseId;//日本人的身份证(子类独有的属性)
//子类独有的方法
public Japanese() {
}
public Japanese(String JapaneseId) {
this.japaneseId = JapaneseId;
}
public String getJapaneseId() {
return japaneseId;
}
public void setJapaneseId(String japaneseId) {
this.japaneseId = japaneseId;
}
public void playVideo(){
System.out.println("日本人:拍电影");
}
}
多个类里有相同的属性和方法就可以抽取出,形成一个共同的父类,减少代码的冗余
public class Test {
public static void main(String[] args) {
Son son = new Son();
}
}
class Father{
public Father() {
System.out.println("父类无参构造");
}
}
class Son extends Father{
public Son() {
//super();默认调用父类的无参构造
System.out.println("子类无参构造");
}
}
继承中的构造方法总结:
创建子类对象会不会调用父类构造方法?
会
创建子类对象调用父类构造方法的目的是什么?
创建子类对象会在堆里开辟空间,调用父类构造方法的目的是在将父类属性拷贝一份存入子类对象中
创建子类对象会创建父类对象吗?
不会
创建子类对象先调用父类构造方法还是子类构造方法?
先调用子类构造方法,子类构造方法中的第一句默认super(),意思是调用父类无参构造
创建子类对象先完成父类构造方法还是子类构造方法?
先完成父类构造方法
super 父类的,与this的使用类似
作用:
super.属性:调用父类的属性
super.方法:调用父类的方法
super():根据传参类型调用父类的构造方法
public class Test {
public static void main(String[] args) {
Chinese c = new Chinese("吴彦祖",18,"123...");
c.playTaiJi();//调用子类的方法
Japanese j = new Japanese("水菜丽",26,"xxx...");
j.playVideo();//调用子类的方法
}
}
//父类
class Person{
private String name;
private int age;
public Person() {
}
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;
}
}
//子类
class Chinese extends Person{
private String chineseId;
public Chinese() {
}
public Chinese(String name, int age, String chineseId) {
super(name, age);//调用父类的有参构造
this.chineseId = chineseId;
}
public String getChineseId() {
return chineseId;
}
public void setChineseId(String chineseId) {
this.chineseId = chineseId;
}
public void playTaiJi(){
//调用父类的方法(间接调用父类的私有化属性)
System.out.println(super.getName() + ":打太极");
}
}
//子类
class Japanese extends Person{
private String japaneseId;
public Japanese() {
}
public Japanese(String name, int age, String japaneseId) {
super(name, age);//调用父类的有参构造
this.japaneseId = japaneseId;
}
public String getJapaneseId() {
return japaneseId;
}
public void setJapaneseId(String japaneseId) {
this.japaneseId = japaneseId;
}
public void playVideo(){
//调用父类的方法(间接调用父类的私有化属性)
System.out.println(super.getName() + ":拍电影");
}
}
所有类的祖先类/超类/基类,一个类没有明确继承某个父类,均自动继承Object
Object作为祖先类,起着类的标杆的作用
方法 | 描述 |
---|---|
equals(Object obj) | 比较两个对象是否一致 |
hashCode() | 返回该对象的hash值 |
getClass() | 返回该类的字节码文件对象 |
toString() | 返回该对象的字符串表示 |
public class Test {
public static void main(String[] args) {
Object obj1 = new Object();
Object obj2 = new Object();
/**
* equals方法:比较两个对象是否一致
* 源码分析:
* public boolean equals(Object obj) {
* return (this == obj);
* }
* 理解:对象==对象,直接比较的是内存地址是否一致
*/
boolean equals = obj1.equals(obj2);
System.out.println(equals);//false
/**
* hashCode方法:获取该对象的hash值
* 源码分析:
* public native int hashCode();//具体实现被java隐私化
* 理解:hash值是通过内存地址+算法 计算出的,但是hash值不等同于内存地址
*/
int hashCode = obj1.hashCode();
System.out.println(hashCode);
/**
* getClass方法:获取该类的字节码文件对象
* 源码分析:
* public final native Class> getClass();//具体实现被java隐私化
* 理解:java是面向对象的语言,在此语言里万物皆对象,字节码文件(.class)也不例外,也是个对 * 象。任意一个类的字节码只加载到内存中一次,所以该类的字节码对象都是相同的
*/
Class c1 = obj1.getClass();
Class c2 = obj2.getClass();
System.out.println(c1);//class java.lang.Object
System.out.println(c2);//class java.lang.Object
System.out.println(c1 == c2);//true
/**
* toString方法:获取该对象的字符串表示
* 源码分析:
* public String toString() {
* return getClass().getName() + "@" + Integer.toHexString(hashCode());
* }
* 理解:返回值是 获取该字节码文件对象的名字 + "@" + 对象hash值的十六进制表示
*/
System.out.println(obj1);//默认调用toString()
System.out.println(obj1.toString());
}
}
做实验证明访问权限
关键字 | 访问权限 |
---|---|
private | 本类 |
默认(什么都不写) | 本类、相同包下 |
protected | 本类、相同包下、子类同包 |
public | 全局 |
如果父类里的方法不满足子类需求时,就可以重写
- 在继承关系中的子类里重写
- 返回值、方法名、参数类型必须和父类一致
- 访问修饰符不能比父类更严格
public class Test {
public static void main(String[] args) {
Student stu1 = new Student("吴彦祖", "班级号6666", "学号001");
Student stu2 = new Student("吴彦祖", "班级号6666", "学号002");
//调用重写后的equals来比较两个对象是否一致
System.out.println(stu1.equals(stu2));//false(学号不一样)
//调用重写后的toString输出想要的对象信息
System.out.println(stu1);//吴彦祖 -- 班级号6666 -- 学号001
System.out.println(stu2);//吴彦祖 -- 班级号6666 -- 学号002
}
}
class Student{
private String name;
private String classId;//班级号
private String id;//学号
public Student() {
}
public Student(String name, String classId, String id) {
this.name = name;
this.classId = classId;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClassId() {
return classId;
}
public void setClassId(String classId) {
this.classId = classId;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
//重写父类的equals方法,好处:重写以后比较两个Student对象就是比较的是两个对象的班级号和学号
@Override
public boolean equals(Object obj) {
Student stu = (Student) obj;//下转型
if(this.classId.equals(stu.classId)
&& this.id.equals(stu.id)){
return true;
}
return false;
}
//重写父类的toString方法,好处:输出Student对象,就可以获取该对象的属性信息
@Override
public String toString() {
return name + " -- " + classId + " -- " + id;
}
}
分包的基本概念:防止类的重名
项目中运用分包:项目中会由很多类,类与类的功能有相同的也有不同的,所以要分包归类管理
项目中的命名规范:com.公司名.项目名.功能名(具体参照公司的命名规范)
ps:
实体类 com.qf.vo/bean/entity
工具类 com.dream.utils/tools
数据库 com.dram.dao
…
#### 概念
final - 最终的
作用:
final修饰类:类不能被继承
final修饰方法:方法不能被重写
final修饰变量:不能被重新赋值,变成常量(存储在常量池中)
//final class Father{//最终的类:不能被继承
class Father{
//public final void method() {//最终的方法:不能被子类重写
public void method() {
System.out.println("父类方法");
}
}
class Son extends Father{
@Override
public void method() {
final int i = 10;
//i = 100;//不能给常量重新赋值
System.out.println("重写父类的方法");
}
}
抽象类:使用abstract修饰
抽闲方法:使用abstract修饰,该方法没有代码块,交给非抽象的子类去重写
思想:抽象类更像是个模板,规定了非抽象的子类应该要完成怎样的方法。当父类里的方法不好实现而该方法又必须写在父类时,可以选择设置为抽象方法,交给非抽象的子类去实现
注意:
- 抽象方法必须在抽象类中
- 抽象类可以没有抽象方法
- 抽象类的子类如果也是抽象类,子类可以不重写父类的抽象方法
- 抽象类的子类如果是非抽象类,子类必须重写父类的抽象方法
- C类继承抽象类B,抽象类B继承抽象类A,那么C类就必须重写A和B的抽象方法
- 抽象类不能new对象
abstract class A{
public abstract void methodA();
}
abstract class B extends A{
public abstract void methodB();
}
class C extends B{
@Override
public void methodB() {
System.out.println("重写抽象B方法");
}
@Override
public void methodA() {
System.out.println("重写抽象A方法");
}
}
abstract class Person{
public abstract void eat();
}
class Chinese extends Person{
@Override
public void eat() {
System.out.println("中国人吃山珍海味");
}
}
class Japanese extends Person{
@Override
public void eat() {
System.out.println("日本人吃马赛克");
}
}
接口,使用interface修饰,是个特殊的抽象类,当抽象类里只有静态常量或抽象方法时,可以用接口代替
注意:
- 接口里可以有静态常量或抽象方法,JDK1.8新特性还添加了默认方法和静态方法
- 接口可以继承多个接口
- 一个类只能继承一个父类,可以实现多个接口
- 接口不能new对象
public class Test {
public static void main(String[] args) {
MyClass m = new MyClass();
m.defaultMethod();//调用I1接口中的默认方法
I1.staticMethod();//调用I1接口中的静态方法
}
}
interface I1{
public abstract void i1Method();
default void defaultMethod(){
System.out.println("I1中的默认方法");
}
public static void staticMethod(){
System.out.println("I1中的静态方法");
}
}
interface I2 extends I3,I4{
public abstract void i2Method();
}
interface I3{
public abstract void i3Method();
}
interface I4{
public abstract void i4Method();
}
class MyClass implements I1,I2{
@Override
public void i3Method() {
System.out.println("实现I3中的抽闲抽象方法");
}
@Override
public void i4Method() {
System.out.println("实现I4中的抽闲抽象方法");
}
@Override
public void i2Method() {
System.out.println("实现I2中的抽闲抽象方法");
}
@Override
public void i1Method() {
System.out.println("实现I1中的抽闲抽象方法");
}
}
interface IPerson{
public abstract void eat();
}
class Chinese implements IPerson{
@Override
public void eat() {
System.out.println("中国人吃山珍海味");
}
}
class Japanese implements IPerson{
@Override
public void eat() {
System.out.println("日本人吃马赛克");
}
}
关系 | 描述 |
---|---|
类与类 | 单继承 |
类与接口 | 多实现 |
接口与接口 | 多继承 |
多种形态
public class Test {
public static void main(String[] args) {
/**
* 需求:老师骑着自行车、汽车上班
*
* 注意:此代码的设计符合OCP(开闭)原则
*
* OCP原则 - OpenClosePrinciple
* 含义:需求升级时,对创建新类是欢迎的,对修改原有类是拒绝的
* 好处:修改原有类容易造成bug
*
* 体现:试一试新加一个飞机类
* 步骤:
* 创建Plane类,继承Vehicle类,
* 修改main方法中Vehicle v = new Plane();
* 注意:修改main方法不算修改,因为是测试代码的
*/
Teacher t = new Teacher();
//类的多态:子类对象指向父类引用,引用里存的是子类对象的地址
//Vehicle v = new Bike();
Vehicle v = new Car();
t.open(v);
System.out.println("老师欣赏沿途的风景...");
t.close(v);
}
}
class Teacher{
public void open(Vehicle v){
//启动
v.start();
}
public void close(Vehicle v){
//关闭
v.stop();
}
}
class Car extends Vehicle{
@Override
public void start() {
System.out.println("汽车开");
}
@Override
public void stop() {
System.out.println("汽车停");
}
}
class Bike extends Vehicle{
@Override
public void start() {
System.out.println("自行车开");
}
@Override
public void stop() {
System.out.println("自行车停");
}
}
abstract class Vehicle{
//交通工具
public void start();
public void stop();
}
public class Test {
public static void main(String[] args) {
/**
* 需求:电脑连接usb,使用鼠标和硬盘
*
* 注意:此代码的设计符合OCP(开闭)原则
*
* 体现:试一试新加一个键盘Keyboard类
* 步骤:
* 创建Keyboard类,实现IUSB接口,
* 修改main方法中IUSB usb = new Keyboard();
* 注意:修改main方法不算修改,因为是测试代码的
*/
Computer com = new Computer();
//接口的多态:实现类对象执行接口的引用,引用里存的是实现类对象的地址
//IUSB usb = new Mouse();
IUSB usb = new Disk();
com.connection(usb);
}
}
class Computer{
//电脑类
public void connection(IUSB usb){
usb.use();
}
}
class Mouse implements IUSB{
@Override
public void use() {
System.out.println("鼠标:左点点、右点点");
}
}
class Disk implements IUSB{
@Override
public void use() {
System.out.println("硬盘:上传文件、下载文件");
}
}
interface IUSB{
//接口
public void use();//使用的抽象方法
}
引用数据的转型
向上转型:子类 转 父类类型
向下转型:父类 转 子类类型,又称为引用数据类型的强转
向上转型就是多态
注意:
- 可以直接调用父类非私有化属性
- 可以直接调用父类非私有化方法
- 可以直接调用子类重写父类的方法
向上转型即多态的缺点:不能调用子类的属性和方法
public class Test {
public static void main(String[] args) {
//向上转型:就是多态
Father f = new Son();
System.out.println(f.fatherStr);//父类属性
f.fatherMethod01();//父类方法01
f.fatherMethod02();//子类重写父类方法02
}
}
class Father{
String fatherStr = "父类属性";
public void fatherMethod01(){
System.out.println("父类方法01");
}
public void fatherMethod02(){
System.out.println("父类方法02");
}
}
class Son extends Father{
String fatherStr = "子类和父类同名的属性";
String sonStr = "子类属性";
public void sonMethod(){
System.out.println("子类方法");
}
@Override
public void fatherMethod02() {
System.out.println("子类重写父类方法02");
}
}
向下转型一定要用instanceof判断对象类型
public class Test {
public static void main(String[] args) {
Animal an = new Dog();//向上转型
//Cat cat = (Cat) an;//直接向下转型容易造成类型转换异常
if(an instanceof Dog){
//判断引用an中指向的对象是否是Dog类
//向下转型
Dog dog = (Dog) an;
}else if(an instanceof Cat){
//判断引用an中指向的对象是否是Cat类
//向下转型
Cat cat = (Cat) an;
}
}
}
class Animal{
//动物类
}
class Dog extends Animal{
}
class Cat extends Animal{
}
使用的抽象方法
}
引用数据的转型
向上转型:子类 转 父类类型
向下转型:父类 转 子类类型,又称为引用数据类型的强转
向上转型就是多态
注意:
- 可以直接调用父类非私有化属性
- 可以直接调用父类非私有化方法
- 可以直接调用子类重写父类的方法
向上转型即多态的缺点:不能调用子类的属性和方法
public class Test {
public static void main(String[] args) {
//向上转型:就是多态
Father f = new Son();
System.out.println(f.fatherStr);//父类属性
f.fatherMethod01();//父类方法01
f.fatherMethod02();//子类重写父类方法02
}
}
class Father{
String fatherStr = "父类属性";
public void fatherMethod01(){
System.out.println("父类方法01");
}
public void fatherMethod02(){
System.out.println("父类方法02");
}
}
class Son extends Father{
String fatherStr = "子类和父类同名的属性";
String sonStr = "子类属性";
public void sonMethod(){
System.out.println("子类方法");
}
@Override
public void fatherMethod02() {
System.out.println("子类重写父类方法02");
}
}
向下转型一定要用instanceof判断对象类型
public class Test {
public static void main(String[] args) {
Animal an = new Dog();//向上转型
//Cat cat = (Cat) an;//直接向下转型容易造成类型转换异常
if(an instanceof Dog){
//判断引用an中指向的对象是否是Dog类
//向下转型
Dog dog = (Dog) an;
}else if(an instanceof Cat){
//判断引用an中指向的对象是否是Cat类
//向下转型
Cat cat = (Cat) an;
}
}
}
class Animal{
//动物类
}
class Dog extends Animal{
}
class Cat extends Animal{
}