今天看见这一行代码我迷茫了…
Map<String, String> errors = new HashMap<>();
为什么我非要用Map接口接收errors对象而不是HashMap?接下来我将把试图说服自己的过程展示出来供大家参考。
注:AI有些回答虽然被我尽可能缩减但这这篇文章依然很长,做好心理准备
我:
java中实现类实现了接口,创建对象为什么要写成
接口 对象名 = new 类名 而不是 子类对象 对象名 = new 类名
AI:
好处:多态性,封装,可扩展性
假设你正在开发一个学校管理系统,其中需要处理不同类型的用户,比如教师(Teacher)和学生(Student),他们都有一些共同的行为,比如登录系统、查看个人信息等。这时,你可以定义一个接口User来表示用户的通用行为:
interface User {
String getUsername();
String getPassword();
void login();
void viewProfile();
}
然后,分别实现这个接口的Teacher和Student类:
class Teacher implements User {
private String username;
private String password;
public Teacher(String username, String password) {
this.username = username;
this.password = password;
}
@Override
public String getUsername() {
return username;
}
@Override
public String getPassword() {
return password;
}
@Override
public void login() {
// 教师登录逻辑
}
@Override
public void viewProfile() {
// 教师查看个人资料逻辑
}
}
class Student implements User {
private String username;
private String password;
public Student(String username, String password) {
this.username = username;
this.password = password;
}
@Override
public String getUsername() {
return username;
}
@Override
public String getPassword() {
return password;
}
@Override
public void login() {
// 学生登录逻辑
}
@Override
public void viewProfile() {
// 学生查看个人资料逻辑
}
}
接下来,当你需要编写一个管理用户登录的模块时,可以使用User接口类型来声明变量,这样无论处理的是教师还是学生,都可以通过统一的接口方法来操作,而无需关注具体的实现细节:
public class LoginManager {
public void loginUser(User user) {
user.login();
// 登录后处理逻辑,比如记录日志等
}
}
使用场景示例:
public static void main(String[] args) {
User teacher = new Teacher("teacher1", "password1");
LoginManager loginManager = new LoginManager();
// 尽管声明为User类型,但可以传入Teacher或Student实例
loginManager.loginUser(teacher);
// 同样可以处理学生登录
User student = new Student("student1", "password2");
loginManager.loginUser(student);
}
在这个例子中,通过使用接口User作为变量类型,LoginManager类的loginUser方法可以透明地处理教师和学生的登录操作,无需知道具体是哪种类型的用户,大大提高了代码的灵活性和可扩展性。如果未来还需要添加新的用户类型(比如管理员Admin),只要实现User接口,就可以直接在现有的系统中使用,无需修改已有的登录逻辑。
我:
Teacher teacher = new Teacher("teacher1", "password1");
LoginManager loginManager = new LoginManager();
这种情况这样也行啊,为什么要用User接口接收
AI:
确实,直接使用具体类如Teacher teacher = new Teacher("teacher1", "password1");
进行实例化也是可行的,特别是在那些上下文中,你确切知道要处理的具体类型,并且不需要利用多态特性时。但是,采用接口(如User user = new Teacher("teacher1", "password1");)
作为变量类型,尤其是在设计更复杂的系统或模块时,提供了几个显著的优势.
让我们继续使用之前的学校管理系统例子,假设我们有一个DisplayUserProfile类,它负责显示用户的基本信息。如果我们直接使用具体类,代码可能会是这样的:
public class DisplayUserProfile {
public void display(Teacher teacher) {
System.out.println("Teacher's Name: " + teacher.getUsername());
// 其他教师特定的展示逻辑
}
}
// 使用
Teacher teacher = new Teacher("teacher1", "password1");
DisplayUserProfile display = new DisplayUserProfile();
display.display(teacher);
在这种情况下,DisplayUserProfile类只能处理Teacher对象。如果我们要处理Student对象,我们需要另一个方法,如display(Student student),这会导致代码重复和冗余。
现在,如果我们使用接口User,情况会有所不同:
public class DisplayUserProfile {
public void display(User user) {
System.out.println("Username: " + user.getUsername());
// 根据User接口的通用属性和行为进行展示逻辑
// 如果需要特定类型的额外信息,可以使用instanceof检查或类型转换
}
}
// 使用
User teacher = new Teacher("teacher1", "password1");
DisplayUserProfile display = new DisplayUserProfile();
display.display(teacher);
User student = new Student("student1", "password1");
display.display(student);
在这个例子中,DisplayUserProfile类可以处理任何实现了User接口的对象,无论是Teacher还是Student。如果需要处理特定类型的信息(如教师的职称或学生的年级),可以使用instanceof关键字检查用户类型,或者安全地转换类型。这种方式让代码更灵活,减少了复制粘贴和重复的代码,同时也为未来的扩展提供了便利。
如果以后需要添加新的用户类型,如Staff,只需要创建一个Staff类实现User接口,DisplayUserProfile类无需任何修改就能处理Staff对象。这就是使用接口带来的优势。
我:
那Map<String, String> errors = new HashMap<>();
和HashMap<String, String> errors = new HashMap<>();
这样使用有没有区别呢
AI:
在实际的Java代码中,Map<String, String> errors = new HashMap<>();
和 HashMap<String, String> errors = new HashMap<>();
在功能上没有区别。它们都会创建一个新的哈希映射(HashMap),其中键(key)和值(value)都是String类型。
然而,它们在编程实践中体现了不同的设计哲学:
- 使用Map<String, String>:
这种做法强调了抽象。变量errors被声明为Map接口类型,意味着你只依赖Map接口提供的公共方法,而不关心具体的实现细节。这样做的好处是,如果将来需要更改映射实现(比如改为LinkedHashMap以保持插入顺序),只需要更改实例化部分,而不会影响使用Map接口的方法。 - 使用HashMap<String, String>:
这种做法更具体,直接声明了HashMap类型。这在你知道需要哈希映射的高效查找性能,并且不打算更换实现时是合适的。如果代码中需要依赖HashMap特有的行为(如无序性、非同步等),那么直接使用HashMap是明确的。
在大多数情况下,推荐使用Map<String, String>,因为这样可以保持代码的抽象性和可扩展性。只有在明确需要HashMap的特性(如性能、无序性等)时,才直接使用HashMap。
总结
很遗憾,我没能说服自己,所以我把它改成HashMap<String, String> errors = new HashMap<>();
等踩坑再说。