我终于明白了什么是阶级
克里斯班
丹尼尔班
我们得到了什么好处?
最后的话
额外提示
有一句话是这么说的:
“每个脑袋都是一个完全不同的世界。”
我认为确实如此true
。有些人可能会说某个老师不懂事,但也许是因为他/她的教学方式与你的大脑“连接方式”不相容。我想这本身就是一种没有对错之分的事情。
许多事情都有不同的解读,这可能会导致宝贵信息的丢失。
所以,今天我想解释一下我是如何class
理解 a 这个概念的。不仅仅是概念上的,还要解释为什么它们在我们的代码中很有用:
当我们开始编程时,我们首先学习的东西之一就是变量和常量。
因此,如果我们的任务是在控制台上打印你的name
和age
,height
你可能会做这样的事情:
注意:我决定不使用class
类似的方式Scanner
来请求用户输入,以使其尽可能简单。
// Java
public class Main {
public static void main(String[] args) {
String name = "Chris";
int age = 23;
double height = 1.85;
System.out.println("name: " + name + ", age: " + age + ", height: " + height);
}
}
这将输出:
name: Chris, age: 23, height: 1.85
伟大的!
但是,现在我们想让变量名更具描述性,添加一个“chris”前缀怎么样?看看吧:
// Java
public class Main {
public static void main(String[] args) {
String chrisName = "Chris";
int chrisAge = 23;
double chrisHeight = 1.85;
System.out.println("chrisName: " + chrisName + ", chrisAge: " + age + ", chrisHeight: " + chrisHeight);
}
}
好的!
现在,让我们添加另一个人的信息:
// Java
public class Main {
public static void main(String[] args) {
String chrisName = "Chris";
int chrisAge = 23;
double chrisHeight = 1.85;
System.out.println("chrisName: " + chrisName + ", chrisAge: " + age + ", chrisHeight: " + chrisHeight);
String danielName = "Daniel";
int danielAge = 27;
double danielHeight = 1.71;
System.out.println("danielName: " + danielName + ", danielAge:" + danielAge + ", danielHeight:" + danielHeight)
}
}
嗯...🤔
你开始看出某种模式了吗?
我们存储了来自两个不同人的相同 3 个值...
这时就需要class
救援了!
person
让我们一步一步地重构我们的代码,每次只关注一个。
克里斯班
在面向对象编程 (OOP) 中,对象classes
被设计为以高内聚性来表示状态和行为。简而言之:这意味着给定对象的变量和方法是相互关联的。如果某个方法不使用对象中的任何变量,则可能表明它不属于它所属的位置。class
class
现在我们有了这个想法,我们可以创建一个具有默认构造函数class
的Chris,它将采用和的值:chrisName
chrisAge
chrisHeight
A
constructor
是一种特殊的函数,它必须与它所属的 具有相同的名称class
+ 没有返回值(甚至不需要void
关键字),通常用于确保 的实例class
位于 中valid state
。
Valid state
表示object
具有预期的值。An
object
是 a 的具体实现class
(我们稍后会看到它的实际作用)。
所以,我们的克里斯class
看起来是这样的:
// Java
public class Chris {
private String name;
private int age;
private double height;
public Chris(String name, int age, double height) {
this.name = name;
this.age = age;
this.height = height;
}
}
关键字
this
用于指代我们的全局范围,class
以便将name
的参数constructor
与实际的全局范围的区分开来name
。
现在我们可以重构我们的代码以便使用我们全新而闪亮的 Chris class
!
因此,不要:
String chrisName = "Chris";
int chrisAge = 23;
double chrisHeight = 1.85;
我们可以有:
Chris chris = new Chris("Chris", 23, 1.85);
该关键字
new
用于指代constructor
我们的 Chrisclass
。并且
chris
(注意小写“c”)就是我们所说的object
,因为它是我们的 Chris 的具体或“真实”实现class
。
但由于我们不再有,chrisName
我们的代码将无法正确编译。chrisAge
chrisHeight
有趣的...
我们怎样才能解决这个问题?
好吧,如果我们回到 Chris 的class
实现,我们可以看到我们的全局作用域变量(也称为fields
、private fields
或member variables
)是private
。因此,我们无法从外部访问它们。
为了能够做到这一点,我们必须添加public
可以帮助我们访问该数据的方法。
// Java
public class Chris {
private String name;
private int age;
private double height;
public Chris(String name, int age, double height) {
this.name = name;
this.age = age;
this.height = height;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public double getHeight() {
return height;
}
}
你注意到 get...() 方法没有使用
this
关键字吗?这是因为没有与它们的名称匹配的参数,所以编译器知道我们引用的是全局作用域的变量。
现在我们有了这些方法,我们可以使用点(.)运算符来访问它们,如下所示:
// Java
public class Main {
public static void main(String[] args) {
Chris chris = new Chris("Chris", 23, 1.85);
System.out.println("chrisName: " + chris.getName() + ", chrisAge: " + chris.getAge() + ", chrisHeight: " + chris.getHeight());
String danielName = "Daniel";
int danielAge = 27;
double danielHeight = 1.71;
System.out.println("danielName: " + danielName + ", danielAge:" + danielAge + ", danielHeight:" + danielHeight)
}
}
那就更好了!
不,等等...
现在我们要为 Daniel 做同样的事情,让我们创建一个 Daniel class
:
丹尼尔班
// Java
public class Daniel {
private String name;
private int age;
private double height;
public Daniel(String name, int age, double height) {
this.name = name;
this.age = age;
this.height = height;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public double getHeight() {
return height;
}
}
现在我们的主要内容class
是:
// Java
public class Main {
public static void main(String[] args) {
Chris chris = new Chris("Chris", 23, 1.85);
System.out.println("chrisName: " + chris.getName() + ", chrisAge: " + chris.getAge() + ", chrisHeight: " + chris.getHeight());
Daniel daniel = new Daniel("Daniel", 27, 1.71);
System.out.println("danielName: " + daniel.getName() + ", danielAge:" + daniel.getAge() + ", danielHeight:" + daniel.getHeight())
}
}
好的!
现在我们的 Mainclass
比以前更短了。
但我们还有一件事要做……
如果你认真想想,我们基本上在 Chris 和 Daniel 内部执行的是相同的逻辑classes
🤔。
这意味着我们没有针对这个特定情况使用正确的抽象。为了找到解决方案,我们需要知道 Chris 和 Daniel 是什么……
没错!他们都是Person
。
因此,如果我们删除 Danielclass
并将 Chris 重命名class
为“Person”,我们的代码最终将变成:
// Java
public class Main {
public static void main(String[] args) {
Person chris = new Person("Chris", 23, 1.85);
System.out.println("chrisName: " + chris.getName() + ", chrisAge: " + chris.getAge() + ", chrisHeight: " + chris.getHeight());
Person daniel = new Person("Daniel", 27, 1.71);
System.out.println("danielName: " + daniel.getName() + ", danielAge:" + daniel.getAge() + ", danielHeight:" + daniel.getHeight())
}
}
我们得到了什么好处?
- 我们的代码现在更短了,但并没有失去它的含义。
- 我们将需要的 2 个新项目减少
classes
到 1 个。 - 我们减少了在更多需要的地方重复“Chris”和“Daniel”的噪音。
- 我们设法在单个中重复使用我们的逻辑
class
。 - 现在我们可以很快知道和都是
chris
同daniel
一个类的具体实现,或者我喜欢称它们为:兄弟。 - 现在我们甚至可以在其他项目中使用这个 Person
class
,它仍然可以正常工作。
最后的话
我希望这个例子能帮助您,先生/女士,理清您对类是什么以及为什么我们在面向对象编程中使用它们的想法:)
下篇文章再见!
额外提示
这一条来自下面的@alphashuroPerson
的评论:另一个好处是,现在我们可以通过创建一个接受对象的函数来替换代码中打印 a 信息的部分Person
,如下所示:
// Java
public class Main {
public static void main(String[] args) {
Person chris = new Person("Chris", 23, 1.85);
printPersonalInfo(chris);
Person daniel = new Person("Daniel", 27, 1.71);
printPersonalInfo(daniel);
}
public static void printPersonalInfo(Person person) {
System.out.println("name: " + person.getName() + ", age:" + person.getAge() + ", height:" + person.getHeight());
}
}
通过这个“小”改动,我们获得了无需维护两行不同代码的好处。如果我们需要以不同的方式呈现某人的信息,代码中只需要修改一处即可。
感谢 Alpha 提出这个问题。
现在,我要对我们的代码进行另一项调整。
由于该printPersonalInfo()
函数只接受Person
对象,这意味着该方法直接依赖于该类Person
。也就是说,它实际上应该是该类的一部分!
因此,让我们继续将函数移动到Person
类中,而不是让它在我们的类中徘徊Main
:
// Java
public class Person {
private String name;
private int age;
private double height;
public Person(String name, int age, double height) {
this.name = name;
this.age = age;
this.height = height;
}
// Imagine we still have the getters here :P
// this is just to make the code block shorter.
public void printInfo() {
System.out.println("name: " + name + ", age:" + age + ", height:" + height);
}
}
现在,您可能已经注意到我必须做一些调整:
- 删除该
person
参数。 - 将每个 Getter 方法调用替换为全局变量。
- 将方法从“printPersonalInfo()”重命名为“printInfo()”。
最后一点可以是可选的,也可以是个人偏好。我个人觉得名称中的“Personal”部分有点多余,因为我们知道Person
稍后会创建一个对象。
好的,现在我们还必须Main
根据这个新实现对我们的课程做一些调整:
// Java
public class Main {
public static void main(String[] args) {
Person chris = new Person("Chris", 23, 1.85);
chris.printInfo();
Person daniel = new Person("Daniel", 27, 1.71);
daniel.printInfo();
}
}
如果你稍微想一想,我们甚至不需要 Getter 方法,这种做事方式与 OOP 的原则之一“封装”相关,这是另一篇文章的主题😉。
🎊 如果你读完整个内容,还能获得额外积分!🎉
文章来源:https://dev.to/chrisvasqm/how-i-finally-understood-what-a-class-is--24pl