Java编程内存分析简要
需求1:计算五名学生,一门课程的平均分。
分析数据存储:
Java语言中存储数据的方式有几种?
(1)简单变量,例如int age;
(2)数组,例如,int []age,定义一个数组相当于一次定义了多个变量,这些变量都是相同类型的。
(3)集合,集合存储不同类型的多个变量
数组存储数据(1)
package tests;
public class Test1 {
public static void main(String[] args) {
//定义数组存储成绩
int[] score = null;
//存入成绩
for(int i = 0; i < score.length;i++) {
score[i] = 80;
}
//打印成绩
for(int i : score) {
System.out.print(i+",");
}
}
}
运行时出现空指针异常。
数组存储数据(2)
Test1
之所以出现空指针异常是由于没有给数组score申请内存,接下来给数组score
申请内存后如下:
package tests;
public class Test2 {
public static void main(String[] args) {
int[] score = new int[5];
for(int i = 0; i < score.length;i++) {
score[i] = 80 + i;
}
for(int i : score) {
System.out.println(i+"分");
}
}
}
数组存储数据(3)
Test2中虽然解决了空指针异常的情况,但是,却无法知道成绩具体所指向的学生是谁??所以要先创建一个学生类(Students),具体如下:
package tests;
public class Test3 {
public static void main(String[] args) {
// 定义引用类型数组
Students[] stu = new Students[2];
// 给数学成绩赋值
for(int i = 0; i < stu.length;i++) {
stu[i].math = 80;
}
//打印成绩
for(Students i : stu) {
System.out.println(i+"分");
}
}
}
解析:出现空指针异常,这是由于只创建了Studnets
类,但是没有创建学生对象new Students();
。
(连学生对象都不存在,如何给学生对象的数学成绩赋值呢,所以报空指针异常。)
解决办法:创建学生后再给数学成绩赋值。
student class
package tests;
public class Students {
int math; //数学成绩
}
Test Class
package tests;
public class Test4 {
public static void main(String[] args) {
Students[] stu = new Students[2];
//创建学生对象
for(int i = 0; i < stu.length;i++) {
stu[i] = new Students();
}
for(int i = 0; i < stu.length;i++) {
stu[i].math = 80 + i;
}
for(Students i : stu) {
System.out.println(i.math+"分");
}
}
}
解释:
首先要明白
基本类型中存储的是真正的数据,引用数据类型存储的都是地址编号。
Students
类是引用数组类型,因此,stu[0]
或stu[1]
存储的是地址,而数学成绩是基本数据类型(int
),其存储的是值。
关于需求1使用面向对象程序设计思想的思考。
相对于简单变量与数组解决这个需求1时,数组更好,因为数组的扩展性好,例如更改了学生数量,数组的维护成本小得多.
但是需求1中的数组实现方式中,如果要增加课程,应该怎么设计呢?显然需要增加数组的个数,让一个数组表示一门课程,有几门课程就定义几个数组。这种设计方法没有体现面向对象的思想,因此无法使用面向对象的特征来解决需求变化的问题.
关于需求1使用面向对象程序设计思想的思考
面向对象认为:万物皆对象,也就是任何事物都是对象.
更具面向对象的思想并结合需求1来设计该程序:
将班级设计为:班级类(名称,学生,平均分)
将学生设计为:学生类(姓名,数学成绩)
将程序启动的文件命名为:Tes t.
Student
package tests;
public class Student {
String name; //姓名
int maht;//数学成绩
}
ClassInfo
package tests;
public class ClassInfo {
String name; //班级名称
Student[] stus = new Student[5];//学生
public int getMathAverage() { //数学成绩平均值
int sum = 0;
for(int i = 0;i < stus.length;i++) {
sum += stus[i].maht;
}
return sum/stus.length;
}
}
Test
package tests;
import java.util.Random;
public class Test {
public static void main(String[] args) {
// 创建班级
ClassInfo cla = new ClassInfo();
cla.name = "史莱克学院n期";
// 输入班级学生的信息
for(int i = 0;i < cla.stus.length;i++) {
cla.stus[i].name = "唐"+(i+1);
cla.stus[i].maht = new Random().nextInt(40) + 60;
System.out.println(cla.stus[i].name + " " + cla.stus[i].maht);
}
// 计算平均数学成绩
int mathAverage = cla.getMathAverage();
System.out.println("数学平均成绩:"+mathAverage);
}
}
运行结果:“java.lang.NullPointerException”
。
分析如下图:
解析:
在创建班级时,学生类也就一并创建了,但是没有创建学生对象;因此在给具体学生对象输入信息时,先要实现对象的实例化。
// 实例化学生对象并输入班级学生的信息
for(int i = 0;i < cla.stus.length;i++) {
cla.stus[i] = new Student(); //实例化学生对象
cla.stus[i].name = "唐"+(i+1);
cla.stus[i].maht = new Random().nextInt(40) + 60;
}
创建学生对象之后,运行后的Java内存分配如下图:
需求2:计算五名学生,三门课程的平均分。
设计类
面向对象中如何分析问题,设计类,设计类的成员.
分析类:找出问题中描述的名词,每个名词设计为一个类.
例如: 统计班级五个学生数学、语文和英语成绩平均分。
其中的 班级, 学生是名词,应该设计为类,因此设计一个班级类和一个学生类,用类图表示类,如下所示
设计类的成员
例如:班级中有学生,因此学生是班级的一个属性;平均分是班级的属性;将班级类设计如下
学生类有数学、语文和英语成绩和学生姓名,学生类的类图如下
代码实现
Student
package tests;
public class Student {
String name; //姓名
int math;//数学成绩
int ch; //语文成绩
int en; //英语成绩
}
ClassInfo
package tests;
public class ClassInfo {
String name; //班级名称
Student[] stus = new Student[5];//学生
int mathAvg; //数学平均成绩
int chAvg; //语文平均成绩
int enAvg; //英语平均成绩
public int getMathAverage() { //数学成绩平均值
int sum = 0;
for(int i = 0;i < stus.length;i++) {
sum += stus[i].math;
}
mathAvg = sum/stus.length;
return mathAvg;
}
public int getChAverage() { //语文成绩平均值
int sum = 0;
for(int i = 0;i < stus.length;i++) {
sum += stus[i].ch;
}
chAvg = sum/stus.length;
return chAvg;
}
public int getEnAverage() { //英语成绩平均值
int sum = 0;
for(int i = 0;i < stus.length;i++) {
sum += stus[i].en;
}
enAvg = sum/stus.length;
return enAvg;
}
}
Test
package tests;
import java.util.Random;
public class Test {
public static void main(String[] args) {
// 创建班级
ClassInfo cla = new ClassInfo();
cla.name = "史莱克学院n期";
// 实例化学生对象并输入班级学生的信息
System.out.println("\n\t\t"+cla.name+"成绩单\n\n\t姓名\t数学\t语文\t英语\n");
for(int i = 0;i < cla.stus.length;i++) {
cla.stus[i] = new Student();//创建学生对象
cla.stus[i].name = "唐"+(i+1);
cla.stus[i].math = new Random().nextInt(40) + 60;
cla.stus[i].ch = new Random().nextInt(40) + 60;
cla.stus[i].en = new Random().nextInt(40) + 60;
System.out.println("\t"+cla.stus[i].name
+ "\t"+cla.stus[i].math
+ "\t"+cla.stus[i].ch
+ "\t"+cla.stus[i].en);
}
// 输出平均成绩
System.out.println("\n\t数学平均成绩:"+cla.getMathAverage());
System.out.println("\t语文平均成绩:"+cla.getChAverage());
System.out.println("\t英语平均成绩:"+cla.getEnAverage());
}
}
增加需求:根据每名同学平均成绩进行排序输出。
第1步:定义排序类
首先按照数学排序,排序类必须是实现了java.util.Comparator
接口的类,并且要实现int compare(Student s1, Student s2)
比较方法,该方法返回int
类型的数据,当返回值大于0
时,表示s1
大于s2
,当返回值等于0
时,表示s1
等于s2
,当返回值小于0
时表示s1
小于s2
.
AverageScoreComparator
package tests;
import java.util.Comparator;
public class AverageScoreComparator implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return (o1.math + o1.ch + o1.en) - (o2.math + o2.ch + o2.en);
}
}
在ClassInfo
类中定义查看成绩的方法shouAvgScore().
public void showAvgScore() {
System.out.println("\t姓名\t平均 成绩");
for(int i = 0;i < stus.length;i++) {
System.out.println("\t"+stus[i].name+"\t平均 成绩"+(stus[i].math + stus[i].ch + stus[i].en)/3);
}
}
第2步:使用Arrays类的sort方法排序
Arrays.sort(cla.stus,new AverageScoreComparator());
完整的测试类如下:
package tests;
import java.util.Arrays;
import java.util.Random;
public class Test {
public static void main(String[] args) {
// 创建班级
ClassInfo cla = new ClassInfo();
cla.name = "史莱克学院n期";
// 实例化学生对象并输入班级学生的信息
System.out.println("\n\t\t"+cla.name+"成绩单\n\n\t姓名\t数学\t语文\t英语\n");
for(int i = 0;i < cla.stus.length;i++) {
cla.stus[i] = new Student();//创建学生对象
cla.stus[i].name = "唐"+(i+1);
cla.stus[i].math = new Random().nextInt(40) + 60;
cla.stus[i].ch = new Random().nextInt(40) + 60;
cla.stus[i].en = new Random().nextInt(40) + 60;
System.out.println("\t"+cla.stus[i].name
+ "\t"+cla.stus[i].math
+ "\t"+cla.stus[i].ch
+ "\t"+cla.stus[i].en);
}
// 输出平均成绩
System.out.println("\n\t数学平均成绩:"+cla.getMathAverage());
System.out.println("\t语文平均成绩:"+cla.getChAverage());
System.out.println("\t英语平均成绩:"+cla.getEnAverage());
System.out.println("排序前三门成绩平均分");
cla.showAvgScore();
Arrays.sort(cla.stus,new AverageScoreComparator());
System.out.println("排序后三门成绩平均分");
cla.showAvgScore();
}
}
结果展示:
需求3:计算多名学生,多门课程的平均分
并按数学、语文、英语和总成绩排序。
分析:
被操作的数据是数学、语文和英语,数学、语文和英语属于学生类;需要操作的内容是平均分,平均分属于班级,人数不确定所以不能使用数组,应该使用集合存储数据。
设计:
设计学生类:定义数学、语文和英语属性
设计班级类:定义学生类的集合,定义班级的平均分,定义计算平均分的方法
设计测试类:运行程序
代码实现
Student
public class Student {
private String name;
private int math;
private int ch;
private int en;
public Student(String name, int math, int ch, int en) {
this.name = name;
this.math = math;
this.ch = ch;
this.en = en;
}
public Student() {
}
public String getName() {
return name;
}
public int getMath() {
return math;
}
public int getCh() {
return ch;
}
public int getEn() {
return en;
}
public void setName(String name) {
this.name = name;
}
public void setMath(int math) {
this.math = math;
}
public void setCh(int ch) {
this.ch = ch;
}
public void setEn(int en) {
this.en = en;
}
}
ClassInfo
import java.util.List;
public class ClassInfo {
private List students;
private int avgMath;
private int avgCh;
private int avgEn;
public List getStudents() {
return students;
}
public void setStudents(List students) {
this.students = students;
}
public int getAvgMath() {
int sum = 0;
for (int i = 0; i < students.size(); i++) {
Student stu = (Student) students.get(i);
sum += stu.getMath();
}
avgMath = sum / students.size();
return avgMath;
}
public int getAvgCh() {
int sum = 0;
for (int i = 0; i < students.size(); i++) {
Student stu = (Student) students.get(i);
sum += stu.getCh();
}
avgCh = sum / students.size();
return avgCh;
}
public int getAvgEn() {
int sum = 0;
for (int i = 0; i < students.size(); i++) {
Student stu = (Student) students.get(i);
sum += stu.getEn();
}
avgEn = sum / students.size();
return avgEn;
}
}
Test
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
// 创建班级
ClassInfo c1 = new ClassInfo();
// 创建学生
Student s1 = new Student("唐1",77,77,77);
Student s2 = new Student("唐2",78,78,78);
Student s3 = new Student("唐3",79,79,79);
Student s4 = new Student("唐4",80,80,80);
Student s5 = new Student("唐5",81,81,81);
// 将学生存储到集合中
List students = new ArrayList();
students.add(s1);
students.add(s2);
students.add(s3);
students.add(s4);
students.add(s5);
// 将集合存储到班级中
c1.setStudents(students);
// 输出学生的平均成绩
System.out.println("平均数学成绩:"+c1.getAvgMath());
System.out.println("平均数学成绩:"+c1.getAvgCh());
System.out.println("平均数学成绩:"+c1.getAvgEn());
}
}
需求4:计算多名学生,多门课程的平均分,并分别按数学、语文、英语成绩排序输出。
只需要在需求3的基础上加以改进就行,不过首先要知道一下两点:
- 对数组排序,java提供了
java.util.Arrays
类,调用sort方法实现排序,需要传入比较器 - 对集合排序,java提供了
java.util.Collections
类,调用sort方法实现排序,需要传入比较器
针对于数学、语文和英语分别进行比较器的设计如下:
MathComparator
import java.util.Comparator;
public class MathComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.getMath() - o2.getMath();
}
}
ChComparator
import java.util.Comparator;
public class ChComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.getCh() - o2.getCh();
}
}
EnComparator
import java.util.Comparator;
public class EnComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.getEn() - o2.getEn();
}
}
接下来还需要在ClassInfo中添加,查看成绩的方法,如下所示:
public void showByMant(){
for (int i = students.size() - 1; i >= 0; i--) {
Student stu = (Student) students.get(i);
System.out.println(stu.getName() + " " + stu.getMath());
}
}
public void showByCh(){
for (int i = students.size() - 1; i >= 0; i--) {
Student stu = (Student) students.get(i);
System.out.println(stu.getName() + " " + stu.getCh());
}
}
public void showByEn(){
for (int i = students.size() - 1; i >= 0; i--) {
Student stu = (Student) students.get(i);
System.out.println(stu.getName() + " " + stu.getEn());
}
}
最后在Test类中添加如下代码就可以测试结果了:
// 数学成绩排序后输出
Collections.sort(c1.getStudents(),new MathComparator());
c1.showByMant();
Collections.sort(c1.getStudents(),new ChComparator());
c1.showByCh();
Collections.sort(c1.getStudents(),new EnComparator());
c1.showByEn();