我的实体类如下:
public class Student {
private int grade;
// other fields and methods
}
我这样使用它:
List<Student> students = ...;
考虑到这是一个私有字段,如何将students
排序为grade
?
答案 0 :(得分:42)
您有以下选择:
grade
可见grade
定义一个吸气方法Comparator
Student
Student
实现Comparable
解决方案3
的示例:
public class Student {
private int grade;
public static Comparator<Student> byGrade = Comparator.comparing(s -> s.grade);
}
并像这样使用它:
List<Student> students = Arrays.asList(student2, student3, student1);
students.sort(Student.byGrade);
System.out.println(students);
这是我最喜欢的解决方案,因为:
Comparator
解决方案4
的示例:
public class Student implements Comparable {
private int grade;
@Override
public int compareTo(Object other) {
if (other instanceof Student) {
return Integer.compare(this.grade, ((Student) other).grade);
}
return -1;
}
}
您可以像这样在任何地方进行排序:
List<Student> students = Arrays.asList(student2, student3, student1);
Collections.sort(students);
System.out.println(students);
此解决方案的方面:
grade
排序代表学生的自然顺序 TreeMap
)答案 1 :(得分:6)
通常,如果您需要的行为取决于学生的成绩,则此信息必须不可访问-添加允许其他代码访问它的方法或属性。
因此,最简单的解决方法是:
public class Student implements IStudent {
...
private int grade;
...
// other fields and methods
public int getGrade() {
return grade;
}
}
您可能还应该扩展接口IStudent
:)
但是,如果只需要排序,则可以采用其他答案中已经提出的想法:实现Comparable
接口。这样,您可以将grade
隐藏起来,并在int compareTo
方法中使用它。
答案 2 :(得分:6)
JDK 1.8提供的一个选项正在使用stream
库sorted()
方法,该方法不需要实现Comparable
接口。
您需要为字段grade
public class Student {
private int grade;
public int getGrade() {
return grade;
}
public Student setGrade(int grade) {
this.grade = grade;
return this;
}}
然后给定具有unsortedStudentList的内容,您可以按照以下代码对其进行排序:
List<Student> sortedStudentList = unsortedStudentList
.stream()
.sorted(Comparator.comparing(Student::getGrade))
.collect(Collectors.toList());
此外,sorted()
方法还使您能够根据其他字段(如果有)对学生进行排序。例如,考虑一个用于学生的字段name
,在这种情况下,您想根据年级和姓名对studentList进行排序。因此Student
类将是这样的:
public class Student {
private int grade;
private String name;
public int getGrade() {
return grade;
}
public Student setGrade(int grade) {
this.grade = grade;
return this;
}
public String getName() {
return name;
}
public Student setName(String name) {
this.name = name;
return this;
}}
要基于两个字段进行排序:
List<Student> sortedStudentList = unsortedStudentList
.stream()
.sorted(Comparator.comparing(Student::getGrade)
.thenComparing(Comparator.comparing(Student::getName)))
.collect(Collectors.toList());
当第一个比较器比较两个相等的对象时,第二个比较器开始起作用。
答案 3 :(得分:4)
为Student类实施Comparable interface,并实现方法int compareTo(T o)
。这样,您可以将成绩属性设置为私有。
答案 4 :(得分:4)
您的课程可以实现Comparable
接口。然后,您可以轻松地对列表进行排序:
public class Student implements IStudent, Comparable<Student>
{
...
private int grade;
...
@Override
public int compareTo(Student other)
{
return (grade - other.grade);
}
}
public class Section
{
private List<IStudent> studentsList;
...
public void sortStudents()
{
studentsList.sort(null);
}
}
答案 5 :(得分:4)
如果您确实需要按字段排序,则无权访问,可以使用反射:
private static int extractGrade(Student student) {
try {
Field field = Student.class.getDeclaredField("grade");
field.setAccessible(true);
return field.getInt(student);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
Comparator<Student> studentComparator = Comparator.comparingInt(DemoApplication::extractGrade);
List<Student> students = Arrays.asList(new Student(1), new Student(10), new Student(5));
students.sort(studentComparator);
}
但是我不得不说这种方法有点不安全。
除非绝对必要,否则不要使用它。例如,最好使用getter方法授予对给定字段的访问权限。
如果您是在模块路径上针对Java 9+运行此代码,也可能会遇到问题(您可能会抛出InaccessibleObjectException
)。
Comparable
来自可比的docs:
此接口对实现该接口的每个类的对象强加了总体排序。此排序称为类的自然排序,而该类的{@code compareTo}方法被称为其自然比较方法。
但是Student
的自然排序是什么?
名字?姓?他们的组合?
对于数字,很容易回答这个问题,但对于Student
之类的类来说,不是很容易。
所以我不认为Student
应该是Comparable
,它们是人类,而不是日期或数字。而且你不能说谁更大,谁平等和谁更小。
答案 6 :(得分:3)
前面提到但未作为示例显示的另一个选项是实现特殊的' class ViewHolder {
@BindView(R.id.title) TextView name;
@BindView(R.id.job_title) TextView jobTitle;
public ViewHolder(View view) {
ButterKnife.bind(this, view);
}
@OnClick(R.id.submit)
public void submit(View view) {
// TODO submit data to server...
}
}'
以便按年级进行比较。
此示例包含一个实现接口Comparator
的类Student
,一个IStudent
和一个使用示例数据的小类StudentGradeComparator
。
进一步的解释以代码注释的形式给出,请仔细阅读
Main
您可以在/**
* A class that compares students by their grades.
*/
public class StudentGradeComparator implements Comparator<IStudent> {
@Override
public int compare(IStudent studentOne, IStudent studentTwo) {
int result;
int studentOneGrade = studentOne.getGrade();
int studentTwoGrade = studentTwo.getGrade();
/* The comparison just decides if studentOne will be placed
* in front of studentTwo in the sorted order or behind
* or if they have the same comparison value and are considered equal
*/
if (studentOneGrade > studentTwoGrade) {
/* larger grade is considered "worse",
* thus, the comparison puts studentOne behind studentTwo
*/
result = 1;
} else if (studentOneGrade < studentTwoGrade) {
/* smaller grade is considered "better"
* thus, the comparison puts studentOne in front of studentTwo
*/
result = -1;
} else {
/* the students have equal grades,
* thus, there will be no swap
*/
result = 0;
}
return result;
}
}
的{{1}}方法中应用此类:
sort(Comparator<? super IStudent> comparator)
仅出于完整性考虑,以下是接口List
及其实现类/**
* The main class for trying out the sorting by Comparator
*/
public class Main {
public static void main(String[] args) {
// a test list for students
List<IStudent> students = new ArrayList<IStudent>();
// create some example students
IStudent beverly = new Student("Beverly", 3);
IStudent miles = new Student("Miles", 2);
IStudent william = new Student("William", 4);
IStudent deanna = new Student("Deanna", 1);
IStudent jeanLuc = new Student("Jean-Luc", 1);
IStudent geordi = new Student("Geordi", 5);
// add the example students to the list
students.add(beverly);
students.add(miles);
students.add(william);
students.add(deanna);
students.add(jeanLuc);
students.add(geordi);
// print the list in an unordered state first
System.out.println("———— BEFORE SORTING ————");
students.forEach((IStudent student) -> {
System.out.println(student.getName() + ": " + student.getGrade());
});
/*---------------------------------------*
* THIS IS HOW YOU APPLY THE COMPARATOR *
*---------------------------------------*/
students.sort(new StudentGradeComparator());
// print the list ordered by grade
System.out.println("———— AFTER SORTING ————");
students.forEach((IStudent student) -> {
System.out.println(student.getName() + ": " + student.getGrade());
});
}
}
:
IStudent
答案 7 :(得分:2)
字母不是一个坏习惯,它们完全是针对您的问题而制作的:访问私有字段以读取它们。
添加吸气剂即可:
studentsList.stream().sorted((s1, s2) -> s1.getGrade()compareTo(s2.getGrade)).collect(Collectors.toList())
更新:如果您确实想将成绩保密,则需要实现Comparable
并覆盖比较方法。
答案 8 :(得分:2)
当您想保持成绩私密时,您可以采用这种方式:
students = students.stream().sorted((s1, s2) -> {
try {
Field f = s1.getClass().getDeclaredField("grade");
f.setAccessible(true);
int i = ((Integer)f.getInt(s1)).compareTo((Integer) f.get(s2));
f.setAccessible(false);
return i;
} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
e.printStackTrace();
}
return 0;
}).collect(Collectors.toList());
答案 9 :(得分:1)
我相信这里最好的选择是在需要排序列表的地方创建一个Comparator
,因为您可能需要按其他位置的其他字段进行排序,这会使您的域类膨胀:
List<Student> sorted = list.stream()
.sorted(Comparator.comparingInt(o -> o.grade))
.collect(Collectors.toList());