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实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Spring AI集成DeepSeek的详细步骤

《SpringAI集成DeepSeek的详细步骤》DeepSeek作为一款卓越的国产AI模型,越来越多的公司考虑在自己的应用中集成,对于Java应用来说,我们可以借助SpringAI集成DeepSe... 目录DeepSeek 介绍Spring AI 是什么?1、环境准备2、构建项目2.1、pom依赖2.2