1、javaBean 是 java 开发中常有的实体类,在 java 开发中符合 javaBean 类的有以下几点:
2、package 关键字作用:定义包
3、import 作用:导入类、第三方工具类
1、为什么要用继承?
为了避免出现重复的代码。
2、继承的作用:实现代码的复用。
3、语法:
class subClass extends superclass{
}
4、特点:
5、代码测试:FatherTest.java
package com.zc.test;
/**
* @author zc
* @date 2021/11/4 14:43
* 继承测试:FatherTest
*
* main(String[] args):主程序入口
*/
public class FatherTest {
/**
* 主程序入口
* @param args 系统参数
*/
public static void main(String[] args) {
// 初始化子类 Son 实例化对象 son
Son son = new Son();
// 给子类 son 继承父类的属性 name 赋值
son.name="张三";
// 给子类 son 继承父类的属性 age 赋值
son.age=18;
// 给子类 son 自己携带的属性 smoking 赋值
son.smoking=true;
// 子类 son 调用继承父类的方法 eat()
son.eat();
// 子类 son 调用自己携带的方法 walk()
son.walk();
System.out.println();
// 输出 son 内存的地址
System.out.println(son.toString());
}
}
/**
* 自定义一个父类:Father
*/
class Father{
/**
* 属性 name:姓名
*/
String name;
/**
* 属性 age:年龄
*/
int age;
/**
* 无参构造器
*/
public Father() {
System.out.println("父类无参");
}
/**
* 有参构造器
* @param name 参数姓名
* @param age 参数年龄
*/
public Father(String name, int age) {
super(); //显式调用父类(Object)的构造器
this.name = name;
this.age = age;
}
/**
* 打印一下
*/
public void eat() {
System.out.println("父类中的吃的行为");
}
}
/**
* 子类 Son 继承父类 Father
*/
class Son extends Father{
/**
* 属性 smoking:吸烟
*/
boolean smoking;
public Son() {
super();
System.out.println("子类无参构造 ");
}
/**
* 方法,打印一下
*/
public void walk() {
System.out.println("走路");
}
}
/**
* 子类 Daughter 继承父类 Father
*/
class Daughter extends Father{
/**
* 属性 beauty:美女
*/
String beauty;
/**
* 打印一下
*/
public void shopping() {
System.out.println("购物");
}
}
运行结果:
父类无参
子类无参构造
父类中的吃的行为
走路
com.zc.test.Son@74a14482
1、方法的重写:方法的覆盖。
2、前提:必须要有继承关系。
3、说到方法重写,看看方法重载的特点:
4、方法重写的特点:
1、多态概念:
一个事物的多种形态(两个或两个以上的类(对象)对同一方法实现了不同的结果)。
2、实现多态方式:
3、代码体现:
父类 对象 = new 子类();
将父类类型作为方法的参数或类的属性是不可以的:子类 对象 = new 父类();。这是错误的。
3、多态的状态:
4、关于类型转换:
5、代码测试,在上面多态测试代码 FatherTest.java 中添加方法 play(Father father):
/**
* 判断父类对象向下转型属于哪个子类
* @param father 父类对象
*/
public static void play(Father father) {
// 调用父类自己的方法
father.eat();
// 如果父类对象 father 是子类对象 Son
if(father instanceof Son) {
// 将父类对象 father 强制转型为 Son 子类,并调用子类自己的方法
((Son)father).walk();
}
// 如果父类对象 father 是子类对象 Daughter
if(father instanceof Daughter) {
// 将父类对象 father 强制转型为 Daughter 子类,并调用子类自己的方法
((Daughter)father).shopping();
}
}
然后在 main 主函数中进行测试:
public static void main(String[] args) {
// 向上转型
Father father = new Daughter();
play(father);
}
运行结果:
父类无参
父类中的吃的行为
购物
1、使用:调用父类的成员。
2、super 调用父类的构造器比较特殊:
this | super | |
---|---|---|
属性 | this 可以调用本类的属性;this 可以调用父类的属性(私有权限不能调用) | super 只能调用父类的属性 |
方法 | this 可以调用本类的方法;this 可以调用父类的方法(私有权限不能调用) | super 只能调用父类的方法 |
构造器(构造方法) | this() 调用的是当前类中的构造器;this() 如果有 N 个构造器最多出现 N-1 个 this([参数]) | super() 显式调用父类的构造器;如果构造器中没有 super():表示隐式调用父类无参构造器 |
特殊 | 当前对象 | 无 |
this 关键字的测试:TestThis.java
/**
* @author zc
* @date 2021/11/30 14:38
* this
*/
public class TestThis {
public static void main(String[] args) {
Boy boy = new Boy();
boy.name="小明";
Girl girl = new Girl();
girl.name="小丽";
boy.marry(girl);
System.out.println("===============================");
girl.marry(boy);
}
}
class Boy{
String name;
public void marry(Girl girl) {
System.out.println("我要娶:"+girl.name);
// this代表的是当前对象 this总结谁调用此方法,那么this就表示那个对象
girl.marry(this);
}
}
class Girl{
String name;
public void marry(Boy boy) {
System.out.println("我要嫁:"+boy.name);
}
}
运行结果:
我要娶:小丽
我要嫁:小明
===============================
我要嫁:小明
属性无多态,方法有多态。
TestAttribute.java
/**
* @author zc
* @date 2021/11/30 14:48
* 属性的多态问题
*/
public class TestAttribute {
public static void main(String[] args) {
A a = new A();
// 10
System.out.println(a.id);
A a1 = new B();
// 10 属性无多态
System.out.println(a1.id);
// B 方法有多态
a1.info();
B b = new B();
// 11
System.out.println(b.id);
// B
b.info();
}
}
class A{
int id = 10;
public void info() {
System.out.println("A");
}
}
class B extends A{
int id = 11;
@Override
public void info() {
System.out.println("B");
}
}
运行结果:
10
10
B
11
B
以上一个 TestAttribute.java 为例,子类 B 继承父类 A,实例化子类对象,分析子类 B 的内存分配方式:
// 实例化子类 B 对象
B b = new B();
// 调用子类B重写父类A的方法
b.info();
为了更清楚多态----父类引用指向子类对象,看看 JVM 的绑定机制。
在 jvm 加载的同时,会在方法区中为这个类存放很多信息,其中有一个数据结构叫方法表,它以数组的形式记录了当前类和所有父类的可见方法字节码在内存中的直接地址。此处 java 基础先不研究 jvm,先看表面的静态绑定与动态绑定。
在编译阶段能够确定方法在内存什么位置的机制就叫静态绑定机制。
所有私有方法、静态方法、构造器及 final 修饰的方法都是采用静态绑定机制。
在编译器阶段就已经指明了调用方法在常量池中的符号引用,JVM运行的时候只需要进行一次常量池解析即可。
比如 Arrays 工具类的调用:
// 静态初始化一个数组
int[] numArr = {12,4,78,56,32};
// 调用 Arrays 工具类对数组排序,此处 sort 方法就是静态绑定机制
Arrays.sort(numArr);
1、什么是动态绑定?
动态绑定是指在 “执行期间”(而非编译期间)判断所引用的实际对象类型,根据其实际的类型调用其相应的方法。
动态绑定是用效率换扩展性,判断的实际对象类型越多越耗时,但拥有很好的扩展性能。
2、实验:DynamicBinding.java
定义三个类:
类成员 | 描述 |
---|---|
color | 几何颜色,属性 String 类型 |
weight | 几何重量,属性 double 类型 |
GeometricObject (String color, double weight) | 有参构造器 |
getter/setter | 属性 getter/setter 方法 |
findArea() | 函数,计算几何的面积,返回 double 类型 |
类成员 | 描述 |
---|---|
radius | 圆半径,属性 double 类型 |
Circle (double radius, String color, double weight) | 有参构造器 |
getter/setter | 属性 getter/setter 方法 |
findArea() | 函数,计算圆的面积,返回 double 类型 |
类成员 | 描述 |
---|---|
width | 矩形的宽,属性 double 类型 |
height | 矩形的高,属性 double 类型 |
MyRectangle (double width, double height, String color, double weight) | 有参构造器 |
getter/setter | 属性 getter/setter 方法 |
findArea() | 函数,计算矩形的面积,返回 double 类型 |
定义一个测试类 DynamicBinding,编写 equalsArea 方法测试两个对象的面积是否相等(注意方法的参数类型,利用动态绑定技术),编写displayGeometricObject 方法显示对象的面积(注意方法的参数类型,利用动态绑定技术)。
import java.math.BigDecimal;
/**
* @author zc
* @date 2021/11/25 14:48
* 多态实验:动态绑定
*
* main(String[] args):主系统入口。
* equalsArea(GeometricObject object1, GeometricObject object2):函数,判断两个几何形状面积是否相等。
* displayGeometricObject(GeometricObject object):函数,显示几何形状的面积。
*/
public class DynamicBinding {
/**
* 主系统入口
* @param args 系统参数
*/
public static void main(String[] args) {
GeometricObject object1 = new Circle(10, "黑色", 2);
displayGeometricObject(object1);
GeometricObject object2 = new MyRectangle(10, 31.4, "黄色", 3);
displayGeometricObject(object2);
equalsArea(object1, object2);
}
/**
* 判断两个几何形状面积是否相等
* @param object1 几何形状 1
* @param object2 几何形状 2
*/
private static void equalsArea(GeometricObject object1, GeometricObject object2){
double area1 = 0.0;
double area2 = 0.0;
if (object1 instanceof Circle){
area1 = ((Circle) object1).findArea();
} else if (object1 instanceof MyRectangle){
area1 = ((MyRectangle) object1).findArea();
}
if (object2 instanceof Circle){
area2 = ((Circle) object2).findArea();
} else if (object2 instanceof MyRectangle){
area2 = ((MyRectangle) object2).findArea();
}
if (area1 != 0.0 && area2 != 0.0){
BigDecimal decimal1 = new BigDecimal(area1);
BigDecimal decimal2 = new BigDecimal(area2);
if (decimal1.equals(decimal2)){
System.out.println("两个几何形状面积相等");
} else {
System.out.println("两个几何形状面积不相等");
}
} else {
System.out.println("几何形状面积不能为 0");
}
}
/**
* 显示几何形状的面积
* @param object 几何形状实例对象
*/
private static void displayGeometricObject(GeometricObject object){
if (object instanceof Circle){
double area = ((Circle)object).findArea();
System.out.println("几何形状为圆,面积为:" + area);
} else if (object instanceof MyRectangle) {
double area = ((MyRectangle)object).findArea();
System.out.println("几何形状为矩形,面积为:" + area);
}
}
}
/**
* 父类--几何形状: GeometricObject
*/
class GeometricObject {
/**
* 属性,几何颜色 color
*/
private String color;
/**
* 属性,几何重量 weight
*/
private double weight;
/**
* 有参构造器
* @param color 参数,几何颜色
* @param weight 参数,几何重量
*/
GeometricObject (String color, double weight) {
this.color = color;
if (weight > 0){
this.weight = weight;
} else {
System.out.println("几何重量要大于 0,不然默认为 10.0");
this.weight = 10.0;
}
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
if (weight > 0){
this.weight = weight;
} else {
System.out.println("几何重量要大于 0,不然默认为 10.0");
this.weight = 10.0;
}
}
public double findArea(){
return 0.0;
}
}
/**
* 子类--圆形:Circle
*/
class Circle extends GeometricObject {
/**
* 属性,半径
*/
private double radius;
/**
* 有参构造器
* @param radius 参数,圆的半径
* @param color 参数,圆的颜色
* @param weight 参数,圆的重量
*/
Circle (double radius, String color, double weight) {
super(color, weight);
if (radius > 0){
this.radius = radius;
} else {
System.out.println("圆的半径要大于 0,不然默认为 10.0");
this.radius = 10.0;
}
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
if (radius > 0){
this.radius = radius;
} else {
System.out.println("圆的半径要大于 0,不然默认为 10.0");
this.radius = 10.0;
}
}
/**
* 重写父类方法,计算圆的面积
* @return
*/
@Override
public double findArea(){
return 3.14 * Math.pow(radius, 2);
}
}
/**
* 子类--矩形:MyRectangle
*/
class MyRectangle extends GeometricObject {
/**
* 属性,矩形宽
*/
private double width;
/**
* 属性,矩形高
*/
private double height;
/**
* 有参构造器
* @param width 参数,矩形宽
* @param height 参数,矩形高
* @param color 参数,矩形颜色
* @param weight 参数,矩形重量
*/
MyRectangle (double width, double height, String color, double weight) {
super(color, weight);
if (width > 0){
this.width = width;
} else {
System.out.println("矩形的宽要大于 0,不然默认为 10.0");
this.width = 10.0;
}
if (height > 0){
this.height = height;
} else {
System.out.println("矩形的高要大于 0,不然默认为 10.0");
this.height = 10.0;
}
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
if (width > 0){
this.width = width;
} else {
System.out.println("矩形的宽要大于 0,不然默认为 10.0");
this.width = 10.0;
}
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
if (height > 0){
this.height = height;
} else {
System.out.println("矩形的高要大于 0,不然默认为 10.0");
this.height = 10.0;
}
}
/**
* 重写父类方法,计算矩形的面积
* @return
*/
@Override
public double findArea(){
return width * height;
}
}
运行结果:
几何形状为圆,面积为:314.0
几何形状为矩形,面积为:314.0
两个几何形状面积相等