java设计一个人派生出学生类_JAVA学习周记(三)

2024-01-28 09:30

本文主要是介绍java设计一个人派生出学生类_JAVA学习周记(三),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1、继承

继承就是在已经存在的类的基础上再进行扩展,从而产生新的类。已经存在的类称为父类、超类或基类,而新产生的类称为子类或派生类。

继承所表达的就是对象类之间的相交关系,它使得某类对象可以继承另外一类对象的数据成员和成员方法。若类B继承类A,则属于B的对象便具有类A的全部或部分性质(数据属性)和功能(操作),我们称被继承的类A为基类、父类或超类,而称继承类B为A的派生类或子类。

代码试例:汽车类{

汽车有四个轮子属性

引擎属性

方向盘属性

如何驾驶()       //方法函数

如何保养()       //方法函数

}

宝马厂家的敞篷跑车继承汽车类

{

如何打开敞篷          //方法函数

}

继承的类型

继承可以分为单继承和多继承。单继承是指一个子类最多只能有一个父类。多继承是一个子类可以有俩个以上的父类。Java语言中的类只支持单继承,多继承是通过接口来间接实现的。

派生类

Java中类的继承是通过extends来修饰的,通过extends的关键字表明前者具备后者的公共的成员变量和方法,再具备了所有公共的成员变量和方法后,本身还能定义一些特有的成员变量和方法。基本语法如下:

访问控制符  [修饰符]  class  类名  extends  父类名{

.........

}

例题:定义一个学生类Student,继承自person类。

定义父类 person 如下:

public class person{

private String name;

private int age;

public void setName(String name){

this.name=name;

}

public String getName(){

return name;

}

public void setAge(String age){

this.age=age;

}

public int getAge(){

return Age;

}

}

定义子类 Student 类如下:

public class Student extends Person{

private String school;

public void setSchool(String school){

this.school=school;

}

public String getSchool(){

return school;

}

public static void main(String[] args){

Student st=new student();

st.setName("奚佳欣");

st.setAge(20);

st.stSchool("西安欧亚学院");

systen.out.println("姓名:  "+st.getName()+"  年龄:  "+st.getAge()+"  学校:  "+st.getSchool());

}

}

以上程序中的Student类扩充了Person类,增加了学校的属性及对应的setter和getter方法,由于Person类中已经存在name和age俩个属性,也就是说此时student类中已经存在了3个属性及3组setter和getter方法,所以在Student类中不需要重新声明着俩个属性,这时就需要考虑是否可以将person类中的内容继续保留到Student类中,也就是继承。

使用super调用父类的构造方法

子类如果想使用父类的构造方法,必须在子类的构造方法中使用,并且必须使用关键字super来表示,而且super必须是子类构造方法中第一个语句。

例题:修改上个例题,分别加入带参数的构造函数

定义父类Person1类:

public class Peson1{

private String name;

private int age;

public Personq(String name ,int age){

this.name = name;

this.age = age;

System.out.println("我是"+this.name);

System.out.println("我的年龄是"+this.age);

}

}

定义子类Student1类:

public class student1 extends Person1{

private String school;

public Student(String name, int age,String school){

super("奚佳欣",20);

this.school = school;

system.out.println("我来自"+this.school);

}

public  static vold  main(String[] ages){

Students st=new Student1("奚佳欣",20,"西安欧亚学院");

}

}

super用法总结:

1.在子类构造方法中要调用父类的构造方法,用"super(参数列表)"的方式调用,参数不是必须的。同时还要注意的一点是:"super(参数列表)"这条语句只能用在字参数构造方法中的第一行。

2.当子类方法中的局部变量或者子类的成员变量与父类变量同名是,也就是子类局部变量父类成员变量事,用“super.成员变量名”来引用父类成员变量。当然,如果父类的成员变量没有被覆盖,也可以用“super.成员变量名”来引用父类成员变量,但这样是不必要的。

3.当子类的成员方法覆盖了父类的成员方法时,也就是子类和父类有完全相同的方法定义(但方法可以不同),此时,用“super.方法名(参数列表)”的方式访问父类的方法。

4.super关键字只能用在类体中非静态部分,如构造函数与成员方法中,若在main()函数中调用或用在静态方法中则会编译出错,报出Cannot use super in a static context 的错误。

泛型数组

1、Java的数组允许在运行时确定数组的大小,但要改变数组的大小就不容易了,解决办法是使用ArrayList类,它是一个采用类型参数的泛型类,如:ArrayList,尖括号里的是类名,表示这个数组列表类里存储的元素是Employee类的对象,如下声明一个保存Employee对象的数组列表:

ArrayList staff = new ArrayList();

2、操作数组列表

① 使用add方法可以将元素添加到数组列表中,如:staff.add(new Employee(“Tom”,...))会添加元素到末尾,如:staff.add(i, e)会添加元素到第i个位置,后面的元素向后移一位

② 使用remove方法删除一个元素,如:

1)staff.remove(1) //表示删除标号为1的元素,并返回被删除的那个元素

2)staff.remove(e) //其中e是一个对象的引用,如果在列表中找到e对象,删除它并返回true,找不到则返回false

③ 可以使用for each循环对数组列表遍历,如:for(Employee e : staff){...}

④ 如果已经清楚或能够估计出数组可能存储的元素数量,就可以在填充数组之前调用ensureCapacity方法,如:staff.ensureCapacity(100)或ArrayList staff = new ArrayList(100)

—— 这个方法和数组的大小有很重要的区别:如果数组分配100个元素的存储空间,数组就有100个空位置可以使用,而容量为100个元素的数组列表只是拥有保存100个元素的潜力,在最初,甚至完成初始化构造之后,数组列表根本就不含有任何元素,此时 数组列表.size() 等于0

⑤ size方法将返回数组列表中包含的实际元素数目,如:staff.size()

⑥ 一旦能够确定数组列表的大小不再发生改变,就可以调用trimToSize方法,这个方法将存储区域的大小调整为当前元素数量所需要的存储空间数目,垃圾回收器将回收多余的存储空间

—— 一旦整理了数组列表的大小,添加新元素就需要花时间再次移动存储块,所以应该在确认不会再添加任何元素时再调用trimToSize

⑦ 对于数组列表变量,如a和b,对于语句:a = b,表示让a和b引用同一个数组列表,并没有发生列表里元素的复制,这点和C++不同

3、访问数组列表元素

① 要设置第i个元素(注:数组列表的下标从0开始),可以:staff.set(i, harry)

—— 只有i小于数组列表大小时才能调用list.set(i,x),例如初始化了一个有存储100个元素潜力的数组列表,此时它的大小为0,所以list.set(0, x)这句是错误的,应使用add方法为数组列表添加新元素,而不要使用set方法,它只负责替换数组中已经存在的元素内容

② 要获得第i个元素,可以:staff.get(i)

③ 想要像数组那样访问数组列表元素,可以使用toArray方法将数组列表元素拷贝到一个数组中:list.toArray(a)

对象包装器与自动打包

1、Java为所有的基本类型提供了相对应的类,称为包装器(Integer、Long、Float、Double、Short、Byte、Character、Void、Boolean(前六个派生于公共的超类Number)),包装器是不可变的,不允许更改包装在其中的值,包装器还是final的,因此不能定义它们的子类,如对于数组列表,这样写是不允许的:ArrayList,需要写成:ArrayList list = new ArrayList()

—— ArrayList的效率远远低于int[]数组,所以此时数组列表更适合构造小型集合,因为这样操作起来更方便

2、自动打包

① 如果把int变量赋给Integer对象,Java会自动打包,如:list.add(3) 会自动换成 list.add(new Integer(3))

② 如果把一个Integer对象赋给int值时,会自动拆包,如:Integer n = 3; n++;等会自动拆开对象包,然后进行计算,最后将结果存入对象包内

—— 注意应避免使用 == 符合来判断两个包装器对象是否相等,因为这有可能是检测的是对象是否指向同一个存储区域,应该使用equals方法来进行比较

—— 打包和拆包是编译器认可的,而不是虚拟机

参数数量可变的方法

使用“...”符号来定义可变参数,如printf方法的定义是:public PrintStream printf(String fmt, Object... args){ },用户自己也可以定义可变参数方法,并将参数指定为任意类型,甚至是基本类型,如下面的代码计算若干个数值的最大值:

public static double max(double... values){

double largest = Double.MIN_VALUE;

for(double v : values)

if(v > largest) largest = v;

return largest;

}

—— 注意,虽然“...”符号在运行程序时类似于把参数变为数组,但并不等价

① 如上面的max方法的参数是“double[] d”,那么在调用max方法应该这样:double d = new double[]{1.0, 2.0}; max(d);或者max(new double[]{1.0, 2.2, 4,3});

② 如果max的参数是“double... values”,那么调用max方法应该这样:max(1.2, 1.3, 2.3);

枚举类

枚举类型(enum type)是指由一组固定的常量组成合法的类型。Java中由关键字enum来定义一个枚举类型。下面就是java枚举类型的定义。

publicenumSeason {

SPRING, SUMMER, AUTUMN, WINER;

}

特点

Java定义枚举类型的语句很简约。它有以下特点:

1) 使用关键字enum 2) 类型名称,比如这里的Season 3) 一串允许的值,比如上面定义的春夏秋冬四季 4) 枚举可以单独定义在一个文件中,也可以嵌在其它Java类中。

除了这样的基本要求外,用户还有一些其他选择

5) 枚举可以实现一个或多个接口(Interface) 6) 可以定义新的变量 7) 可以定义新的方法 8) 可以定义根据具体枚举值而相异的类

用法

a7035ce3a27e

常量

a7035ce3a27e

switch

a7035ce3a27e

向枚举中添加新方法

a7035ce3a27e

覆盖枚举的方法

a7035ce3a27e

实现接口

a7035ce3a27e

使用接口组织枚举

反射

在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制。通俗点讲,通过反射,该类对我们来说是完全透明的,想要获取任何东西都可以。

想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到我们想要的所有信息(方法,属性,类名,父类名,实现的所有接口等等),每一个类对应着一个字节码文件也就对应着一个Class类型的对象,也就是字节码文件对象。

获取字节码文件对象的三种方式。

1、Class clazz1 = Class.forName("全限定类名");  //通过Class类中的静态方法forName,直接获取到一个类的字节码文件对象,此时该类还是源文件阶段,并没有变为字节码文件。

2、Class clazz2  = Person.class;    //当类被加载成.class文件时,此时Person类变成了.class,在获取该字节码文件对象,也就是获取自己, 该类处于字节码阶段。

3、Class clazz3 = p.getClass();    //通过类的实例获取该类的字节码文件对象,该类处于创建对象阶段

继承设计的技巧

(1)将公共操作和域放置在超类

(2)不要使用受保护的域

有些程序员认为,将大多数的实例域定义为protected是一个不错的主意,只有这样,子类才能够在需要的时候直接访问他们。然而,protected 机制并不能够带来更好的保护,其原因主要有两点。第一,子类集合是无限制的,任何一个人都能够由某个类派生一个子类,并编写代码以直接访问 protected的实例域,从而破坏了封装性。第二,在Java程序设计语言中,在同一个包中的所有类都可以访问protected域,而不管它是否为 这个类的子类。

(3)使用继承实现“is-a”关系

使用继承很容易得到节省代码的目的,但有时候也被人们滥用了。例如,假设需要定义一个钟点工(Contractor)类。钟点工的信息包含姓名和雇佣日 期,但是没有薪水。他们按小时计薪,并且不会因为拖延时间而获得加薪。这似乎在诱导人们由Employee派生出子类Constractor,然后再增加 一个hourlyWage域。

class Contractor extends Employee

{

….

private double hourlyWage;

}

这并不是一个好主意。因为这样一来,每个钟点工对象中都包含了薪水和计时工资这两个域。在实现打印支票或税单方法的时候,会到来无尽的麻烦,并且会多些很多代码。

钟点工与雇员之间不属于“is-a”关系。钟点工不是特殊的雇员。

(4)除非所有继承的方法都有意义,否则不要使用继承。

假设想编写一个Holiday类。毫无疑问,每个假日也是一日,并且一日可以用GregorianCalendar类的实例表示,因此可以使用继承。

class Holiday extends GregorianCalendar

{

………….

}

很遗憾,在继承的操作中,假日集不是封闭的。在GregorianCalendar中有一个共有方法add,可以将假日转换成非假日:

Holiday Christmas;

christmas.add(Calendar.DAY_OF_MONTH,12);

因此,继承对于这个例子来时并不太适宜。

(5)在覆盖方法的时候,不要改变预期的行为。

置换原则不仅应用于语法,而且也可以应用于行为,这似乎更加重要。在覆盖一个方法的时候,不应该毫无缘由的改变行为的内涵。就这一点而言,编译器不会提供 任何帮助,即编译器不会检查重定义的方法是否有意义。例如,可以重定义Holiday类中的add方法“修正”原方法的问题,或什么也不做,或抛出一个异 常,或继续到下一个假日。然而这些都违反了置换原则,语句序列

int d1=x.get(Calendar.DAY_OF_MONTH);

x.add(Calendar.DAY_OF_MONTH,1);

int d2=x.get(Calendar.DAY_OF_MONTH);

System.out.println(d2-d1);

不管x属于GregorianCalendar类,还是属于Holiday类,执行上述语句后都应该得到预期的行为。

当然,这样可能会引起某些争议。人们可能就预期行为的含义争论不休。例如,有些人争论说,置换原则要求Manager.equals不处理bonus域, 因为Employee.equals没有它。实际上,凭空讨论这些问题毫无意义。关键在于,在覆盖子类中的方法时,不要偏离最初的实际想法。

(6)使用多态,而非类型信息。

无论什么时候,对于下面这种形式的代码:

if(x is of type1)

action1(x);

else if (x is of type2)

action2(x)

都应该考虑使用多态性。

action1与 action2表示的是相同的概念吗?如果是相同的概念,就应该为这个概念定义一个方法,并将其放置在两个类的超类或接口中,然后,就可以调用x.action( );以便使用多态性提供的动态分派机制执行相应的动作。

使用多态犯法或接口编写的代码比使用对多种类型进行检测的代码更加易于为何和扩展。

(7)不要过多地使用反射

反射机制使得人们可以通过在运行时查看域和方法,让人们编写出更具有通行的程序。这种功能对于编写系统程序来说及其实用,但是通常不是用于编写应用程序。反射是很脆弱的,即编译器很难帮助人们发现程序中的错误。任何错误只能在运行时才被发现,并导致异常。

这篇关于java设计一个人派生出学生类_JAVA学习周记(三)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/653218

相关文章

Java编译生成多个.class文件的原理和作用

《Java编译生成多个.class文件的原理和作用》作为一名经验丰富的开发者,在Java项目中执行编译后,可能会发现一个.java源文件有时会产生多个.class文件,从技术实现层面详细剖析这一现象... 目录一、内部类机制与.class文件生成成员内部类(常规内部类)局部内部类(方法内部类)匿名内部类二、

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Springboot @Autowired和@Resource的区别解析

《Springboot@Autowired和@Resource的区别解析》@Resource是JDK提供的注解,只是Spring在实现上提供了这个注解的功能支持,本文给大家介绍Springboot@... 目录【一】定义【1】@Autowired【2】@Resource【二】区别【1】包含的属性不同【2】@

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

Elasticsearch 在 Java 中的使用教程

《Elasticsearch在Java中的使用教程》Elasticsearch是一个分布式搜索和分析引擎,基于ApacheLucene构建,能够实现实时数据的存储、搜索、和分析,它广泛应用于全文... 目录1. Elasticsearch 简介2. 环境准备2.1 安装 Elasticsearch2.2 J

Java中的String.valueOf()和toString()方法区别小结

《Java中的String.valueOf()和toString()方法区别小结》字符串操作是开发者日常编程任务中不可或缺的一部分,转换为字符串是一种常见需求,其中最常见的就是String.value... 目录String.valueOf()方法方法定义方法实现使用示例使用场景toString()方法方法

Java中List的contains()方法的使用小结

《Java中List的contains()方法的使用小结》List的contains()方法用于检查列表中是否包含指定的元素,借助equals()方法进行判断,下面就来介绍Java中List的c... 目录详细展开1. 方法签名2. 工作原理3. 使用示例4. 注意事项总结结论:List 的 contain

Java实现文件图片的预览和下载功能

《Java实现文件图片的预览和下载功能》这篇文章主要为大家详细介绍了如何使用Java实现文件图片的预览和下载功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... Java实现文件(图片)的预览和下载 @ApiOperation("访问文件") @GetMapping("

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis