员工类 Employee, 经理类:Manager

  1. public class Employee {
  2. private String name;
  3. private double salary;
  4. private LocalDate hireDay;
  5. public Employee(String n, double s, int year, int month, int day){
  6. this.name = n;
  7. this.salary =s;
  8. this.hireDay = LocalDate.of(year, month, day);
  9. }
  10. public String getName() {
  11. return name;
  12. }
  13. public double getSalary() {
  14. return salary;
  15. }
  16. public LocalDate getHireDay() {
  17. return hireDay;
  18. }
  19. public void raiseSalary(double byPercent){
  20. double raise = salary * byPercent / 100;
  21. this.salary += raise;
  22. }
  23. }

  1. class Manager extends Employee{
  2. private double bonus;
  3. public Manager(String n, double s, int year, int month, int day, double bonus){
  4. super(n,s,year,month,day); //调用父类构造函数
  5. this.bonus = bonus;
  6. }
  7. public void setBonus(double bonus){
  8. this.bonus = bonus;
  9. }
  10. @Override
  11. public double getSalary(){
  12.      //double baseSalary = this.salary;  //Error 'salary' has private access in 'Employee'
  13.      //double baseSalary = this.getSalary();  //无限嵌套调用本身
  14. double baseSalary = super.getSalary();
  15. return baseSalary + bonus;
  16. }
  17. }
  1. public class Test1 {
  2. public static void main(String[] args) throws InterruptedException {
  3. Employee boss = new Manager("boss", 1000000, 2011, 5, 1, 500000);
  4. //boss.setBonus(600000); 编译错误,无法找到setBonus
  5. System.out.println(boss.getName());
  6. System.out.println(boss.getSalary());
  7. }
  8. }

  1. extends 关键字表示类之间的继承关系。子类继承基类中的所有方法和数据。

  2. 重写覆盖基类方法。当有些基类方法并不适用于子类时,可以重写该方法。Manager类 增加了数据bonus,在计算薪水的时候getSalary理应也要把bonus加进去。子类实例可以调用继承的基类public成员(包括方法和数据),但private成员只有Employee类自己可见。当在Manager中使用this.salary时会报 'salary' has private access in 'Employee' 的错误。this.getSalary()是调用子类函数getSalary本身。这时可以用super指代基类,调用基类方法 —> super.getSalary();

  3. 可以使用基类的变量指向子类实例,如上Employee boss = new Manager("boss", 1000000, 2011, 5, 1, 500000);  在调用方法时是实例去调用,即boss.getSalary()输出的是 1000000 + 500000。但不能调用子类独有的方法,如setBonus,会造成编译错误。

  一个对象变量可以引用多种实际类型------->多态:    上例代码 boss可以指向Manager实例,当然也可以指向Employee实例。

  4. 子类构造函数可以在第一句使用super(param)的方式显示调用基类的构造函数。如果没有显式调用,则将自动调用基类的默认构造函数,如果基类没有默认构造函数,则会编译错误。也就是说子类的构造函数总是要先执行基类构造。

  5. final 修饰变量, 变量只能初始化一次; 修饰方法,方法不能被子类重写; 修饰类, 类不能被继承。

  6. 抽象类。abstract关键字修饰抽象类和抽象方法。包含抽象方法的类本身必须被声明为抽象类。抽象类可以包含具体数据和具体方法。抽象类不能被实例化。

  7. 重写equals方法,多有类都派生于Object类,Object类的equals源码如下,直接比较引用,这对很多其他类并不适用:

  1. public boolean equals(Object obj) {
  2. return (this == obj);
  3. }
  •     应该重写Object中的equals,应该定义为 public boolean equals(Object otherObject),不要改变参数类型,否则就不是重写了;
  •     if(this == otherObject) 优化,地址相等直接返回。
  •     检测otherObject是否为空, 即if(otherObject == null) return false;
  •     比较this和otherObject是否属于同类。如果equals在每个子类中都有自己的定义,则应该使用getClass判断类型。如果所有子类都有统一的语义,则可使用 if(!otherObject instanceof ClassName)return false;
  •     将otherObject转换为相应类型的变量, ClassName other = (ClassName)otherObject;
  •     比较数据,基本类型 使用 ==比较。类类型可使用Objects.equals比较。

   8. hashCode 由Object类定义的,返回一个整型值。源码:public native int hashCode(); 详细信息见下面的注释。

看源码的注释

  1. /**
  2. * Returns a hash code value for the object. This method is
  3. * supported for the benefit of hash tables such as those provided by
  4. * {@link java.util.HashMap}.
  5. * <p>
  6. * The general contract of {@code hashCode} is:
  7. * <ul>
  8. * <li>Whenever it is invoked on the same object more than once during
  9. * an execution of a Java application, the {@code hashCode} method
  10. * must consistently return the same integer, provided no information
  11. * used in {@code equals} comparisons on the object is modified.
  12. * This integer need not remain consistent from one execution of an
  13. * application to another execution of the same application.
  14. * <li>If two objects are equal according to the {@code equals(Object)}
  15. * method, then calling the {@code hashCode} method on each of
  16. * the two objects must produce the same integer result.
  17. * <li>It is <em>not</em> required that if two objects are unequal
  18. * according to the {@link java.lang.Object#equals(java.lang.Object)}
  19. * method, then calling the {@code hashCode} method on each of the
  20. * two objects must produce distinct integer results. However, the
  21. * programmer should be aware that producing distinct integer results
  22. * for unequal objects may improve the performance of hash tables.
  23. * </ul>
  24. * <p>
  25. * As much as is reasonably practical, the hashCode method defined by
  26. * class {@code Object} does return distinct integers for distinct
  27. * objects. (This is typically implemented by converting the internal
  28. * address of the object into an integer, but this implementation
  29. * technique is not required by the
  30. * Java&trade; programming language.)

1. 这方法是用来优化hash tables的,例如 HashMap。

2. 只要对象数据没有改变(equals方法中使用的数据),不论什么时候去获取hashCode,都应该也一样。但不是不允许hashCode变化。

3.两个对象如果equals判定相等, 必须有相同的hashCode

4. 当equals判定两个对象不相等时,并不要求hashCode一定不相等。但是要明白,不同对象(equals比较)有不同的hashCode可以提高 哈希表的性能。

5. Object类的hashCode方法返回的是由地址转换的整型。不同对象hashCode不同。 它是native方法,其他语言实现的。

hashCode()方法被定义是用来使得哈希表可以高效工作的。hashCode 为什么对哈希表很重要呢? 例如我们用的 HashMap,当我们调用get(Object  key)时,首先就要查找在容器中是否存在这个对象,一般来说如何查找,肯定是要逐个去比较是否相等的,那就要使用equals方法才正确。但如果数据很多,equals的工作效率就很慢。这个时候就要有一个代替的方案:hashCode。当我们调用哈希容器的get(Object obj)方法时,首先查找是否有相同哈希值的对象,如果有再用equals比较是否相等,相等则返回该哈希处的对象。否则当然都是null,hashCode()返回的是一个整型值,比较自然很快。

总结:

  • 重写equals,必须要重写hashCode。equals判定相等,hashCode必须一致。
  • equals是判定两对象是否相等的充要条件。
  • hashCode方法是判定两对象是否相等的必要非充分条件。

在重写hashCode时,最好使用null安全的Objects.hashCode方法。或者当需要组合多个散列值时,调用Objects.hash方法直接生成。我们重写Employee类的equals和hashCode方法。

  1. public boolean equals(Object otherObject)
  2. {
  3. // a quick test to see if the objects are identical
  4. if (this == otherObject) return true;
  5. // must return false if the explicit parameter is null
  6. if (otherObject == null) return false;
  7. // if the classes don't match, they can't be equal
  8. if (getClass() != otherObject.getClass()) return false;
  9. // now we know otherObject is a non-null Employee
  10. Employee other = (Employee) otherObject;
  11. // test whether the fields have identical values
  12. return Objects.equals(name, other.name) && salary == other.salary && Objects.equals(hireDay, other.hireDay);
  13. }
  1. public int hashCode(){
  2. return 7 * Objects.hashCode(name) + 11 * new Double(salary).hashCode() + 13 * hireDay.hashCode();
  3. }
  4. public int hashCode()
  5. {
  6. return Objects.hash(name, salary, hireDay);
  7. }

计算数组类型的hashCode 可以使用 Arrays.hashCode(type[] a)方法。

9. 对象包装器类: Integer、Long、Float、Double、Short、Byte、Character、Void、Boolean。都是不可变类型。自动装拆箱。

10. "..."表示接受任意数量的对象。例如  Object...  同等于Object[]。

11. 反射。

  • Class 类。
  1. Class cl = object.getClass(); //Object的getClass方法返回一个Class类型的实例,一个Class对象表示一个特定类的属性。
  2. String className = new Date().getClass().getName() //值为"java.util.Date", cl.getName()返回该类的名字,名字包含包名.

这样我们就可以从一个对象实例获得其Class对象和类名。同样我们也可以通过类名获得对应的Class对象并构建类实例。

  1. String className = "java.util.Date";
  2. Class cl = Class.forName(className); //forName方法只有在className字符串是类名或接口名时才能够执行,否侧会抛checked exception。
  3. //获得Class对象的另一种方法。T.class。T为java的任意类型
  4. Class cl1 = Date.class;
  5. Class cl2 = int.class;
  6. Class cl3 = Double[].class;
  7. //通过Class对象的newInstance()方法创建类的实例。
  8. Date now = (Date)cl.newInstance();
  9. //newInstance方法调用默认的构造函数初始化对象。如果没有默认或者无参的构造函数将报错。

这样我们就可以通过字符串获得具体需要执行的类,例如将类名写在配置文件中,在需要更换类的时候就不必再更改代码了。

  1. String classNameStr = readFromProperties; //"ClassA"
  2. Class c = Class.forName(classNameStr);
  3. ClassAInterface factory = (ClassAInterface)c.newInstance();

当按类名构造类实例需要传入参数时,可以使用 Constructor类的newInstance()方法。

  • 分析类的能力

  java.lang.reflect包中有三个类,Field、Method、Constructor,分别用于描述类的属性、方法、和构造器。 Class和这三个类都有一个方法叫做getModifiers(),该方法返回一个整型值,表示类、数据、方法和构造器的修饰属性,例如 1 表示public,可以使用Modefier类分析返回的值。这三个类也都有getName方法返回名称。

Class类

getName()

getSuperclass()

getModifiers()

getFields()---返回public 数据,getDeclareFields ---返回所有数据-----Field类

getMethods()---返回public 方法, getDeclareMethods---返回所有方法---Method类

getConstructors()---返回public 构造器,getDeclareConstructors--返回所有构造器---Constructor类

newInstance()

static forName

  Field

getName()

getType()----返回类型,Class对象

getModifiers()

  Method

getName()

getReturnType()

getModifiers()

getParameterTypes()

  Constructor

getName()

getModifiers()

getParameterTypes()

  • 运行时使用反射分析对象

  通过反射机制查看对象的数据,例:

  1. Employee marry = new Employee("Marry", 50000,2022, 8, 1);
  2. Class c = marry.getClass();
  3. Field f = c.getDeclaredField("name");
  4. f.setAccessible(true); //Importance setAccessible方法 设置为true时,使得Field.get()方法可以访问private属性。
  5. /**
  6. AccessibleObject类的静态方法setAccessible()如下,可以设置Field[]为可读取的。
  7. public static void setAccessible(AccessibleObject[] array, boolean flag)
  8. */
  9. String name = (String)f.get(marry); //Field.get() 方法返回的类型为Object,String类可以,但是当访问salary属性时就不行了,
  10. //基本类型不是Object的子类,这时可以使用Field.getDouble()方法。
  •  通过invoke调用任意方法

这种方法不推荐使用, Method m1 = Employee.class.getMethod("raiseSalary", double.class);  m1.invoke(10) 当有返回值时,invoke返回的都是Object对象。

java基础二、类与继承的更多相关文章

  1. 【代码笔记】Java基础:类的继承(构造器)

    在Java中,创建对象的格式为: 类名 对象名 = new 类名(): 如: 1 JFrame jf = new JFrame(); 一个对象被创建出来时,经常要先做一些事这个对象才能正常使用,也可以 ...

  2. Java基础 -- 复用类(组合和继承)

    复用类有两种实现方式. 在新的类中产生现有类的对象,由于新的类是由现有类的对象所组成,所以这种方法称之为组合. 采用继承实现. 一  组合语法 下面创建两个类WaterSource和Sprinkler ...

  3. java基础/一个类A继承了类B,那么A就叫做B的派生类或子类,B就叫基类或超类。

    类重复,pulic class demo1 和class demo1 重复 无主类, 在cmd中输入命令: SET CLASSPATH=. (等号后为英文点符号),即可设置解释的路径为当前路径. 再次 ...

  4. Java基础-StringBuffer类与StringBuilder类简介

    Java基础-StringBuffer类与StringBuilder类简介 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.StringBuffer类 在学习过String类之后 ...

  5. Java面试题总结之Java基础(二)

    Java面试题总结之Java基础(二) 1.写clone()方法时,通常都有一行代码,是什么? 答:super.clone(),他负责产生正确大小的空间,并逐位复制. 2.GC 是什么? 为什么要有G ...

  6. 《Java基础——线程类》

    Java基础--线程类       一.线程的创建之Thread类: 规则: 通过声明一个新类作为子类继承 Thread 类,并复写 run() 方法,就可以启动新线程并执行自己定义的 run()方法 ...

  7. 第二十九节:Java基础知识-类,多态,Object,数组和字符串

    前言 Java基础知识-类,多态,Object,数组和字符串,回顾,继承,类的多态性,多态,向上转型和向下转型,Object,数组,多维数组,字符串,字符串比较. 回顾 类的定义格式: [类的修饰符] ...

  8. java基础-BigDecimal类常用方法介绍

    java基础-BigDecimal类常用方法介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.BigDecimal类概述 我们知道浮点数的计算结果是未知的.原因是计算机二进制 ...

  9. java基础-BigInteger类常用方法介绍

    java基础-BigInteger类常用方法介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.BigInteger类概述 Java中long型为最大整数类型,对于超过long ...

  10. java基础-Arrays类常用方法介绍

    java基础-Arrays类常用方法介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Array类的概念 此类包含用来操作数组(比如排序和搜索)的各种方法.需要注意,如果指定 ...

随机推荐

  1. 2022年字节跳动基础架构前端实习生凉经(4轮技术面+hr面)

    技术一面 原文链接:https://juejin.cn/post/7120516854203809829 因为我之前的项目经验有开发小程序的,所以一开始就问了小程序的问题 1.小程序onload和on ...

  2. 在 macOS 上搭建 Flutter 开发环境

    下载 Flutter SDK flutter官网下载:https://flutter.io/sdk-archive/#macos 若上述链接无法访问,可通过GitHub下载 https://githu ...

  3. Apache DolphinScheduler新一代分布式工作流任务调度平台实战-中

    @ 目录 架构设计 总体架构 启动流程图 架构设计思想简述 负载均衡 缓存 实战使用 参数 参数优先级 内置参数 基础内置参数 衍生内置参数 本地参数和全局参数 工作流传参 数据源管理 支持数据源 创 ...

  4. PROFIBUS,PROFINET,Ethernet三者的区别

    PROFIBUS,PROFINET,Ethernet三者的区别 简单一点说,PROFINET=PROFIbus+etherNET,把Profibus的主从结构移植到以太网上,所以profinet会有C ...

  5. 【原创】Python 二手车之家车辆档案数据爬虫

    本文仅供学习交流使用,如侵立删! 二手车之家车辆档案数据爬虫 先上效果图 环境 win10 python3.9 lxml.retrying.requests 需求分析 需求: 主要是需要车辆详情页中车 ...

  6. ROS机械臂 Movelt 学习笔记4 | Move Group 接口 Python

    Python 的使用总是比 C++ 简单许多,Move Group 的 Python 接口更为便捷,也为使用者提供了很多用于操纵机器人和机械臂的函数,能够和 C++ 接口实现相同的功能: 设置机械臂的 ...

  7. 技术分享 | MySQL Group Replication集群对IP地址的限制导致的一些问题与解决办法

    GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 1. 遇到问题 测试人员小玲准备在docker环境中部署MGR集群进行一些测试,她有三个容器,容器IP分别是: 172.3 ...

  8. 从零搭建云原生技术kubernetes(K8S)环境-通过kubesPhere的AllInOne方式

    前言 k8s云原生搭建,步骤有点多,但通过kubesphere,可以快速搭建k8s环境,同时有一个以 Kubernetes 为内核的云原生分布式操作系统-kubesphere,本文将从零开始进行kub ...

  9. Word 段前分页是什么?怎么设置?

    描述 这两个标题在第一个标题的页中,且两个标题都没有独立分页.要让每一个标题独立分页,需要对标题的格式进行修改. 段前分页指的是标题与标题之间不在同一个页中,每一个标题都在独立的页中. 设置段前分页 ...

  10. HDU2065 “红色病毒”问题 (指数型母函数经典板题)

    题面 医学界发现的新病毒因其蔓延速度和Internet上传播的"红色病毒"不相上下,被称为"红色病毒",经研究发现,该病毒及其变种的DNA的一条单链中,胞嘧啶, ...