我开始学习 OOP,我想了解什么是类。我对某些核心元素的使用松散程度感到有些困惑,从而增加了我的困惑。
我看过 C++ 类,java 类,我想知道足够的知识来编写我自己的伪类来帮助我理解。
例如,在这篇文章中,我读到了这个(.. 类属性(或类属性、字段或数据成员)
我已经看到了一些很好的问题,这些问题表明类属性和类字段之间存在差异,例如C# 中的字段和属性之间有什么区别?
根据我正在学习的语言,是
- 财产
- 字段
- 类变量
- 属性
因语言而异?
我开始学习 OOP,我想了解什么是类。我对某些核心元素的使用松散程度感到有些困惑,从而增加了我的困惑。
我看过 C++ 类,java 类,我想知道足够的知识来编写我自己的伪类来帮助我理解。
例如,在这篇文章中,我读到了这个(.. 类属性(或类属性、字段或数据成员)
我已经看到了一些很好的问题,这些问题表明类属性和类字段之间存在差异,例如C# 中的字段和属性之间有什么区别?
根据我正在学习的语言,是
因语言而异?
“字段”、“类变量”和“属性”或多或少是相同的——附加到对象的低级存储槽。每种语言的文档可能始终使用不同的术语,但大多数实际程序员可以互换使用它们。(但是,这也意味着某些术语可能是模棱两可的,例如“类变量” - 它可以解释为“给定类的实例的变量”,或“类对象本身的变量”其中类对象是您可以直接操作的东西。)
在我使用的大多数语言中,“属性”是完全不同的东西——它们是一种将自定义行为附加到读/写字段的方法。(或更换它。)
所以在 Java 中,典型的例子是:
class Circle {
// The radius field
private double radius;
public Circle(double radius) {
this.radius = radius;
}
// The radius property
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
// We're doing something else besides setting the field value in the
// property setter
System.out.println("Setting radius to " + radius);
this.radius = radius;
}
// The circumference property, which is read-only
public double getCircumference() {
// We're not even reading a field here.
return 2 * Math.PI * radius;
}
}
(请注意,在 Java 中,属性foo
是一对被调用的访问器方法getFoo()
-setFoo()
或者如果属性是只读的,则只是 getter。)
另一种看待这一点的方式是,“属性”是一种抽象——对象承诺允许调用者获取或设置一段数据。而“字段”等是这种抽象的一种可能实现。上面例子中的值getRadius()
可以getCircumference()
直接存储,也可以计算出来,调用者无所谓;setter 可能有也可能没有副作用;呼叫者无关紧要。
我同意你的看法,由于许多 OO 术语的定义松散和使用不一致,有很多不必要的混淆。您所询问的术语在某种程度上可以互换使用,但可以说有些术语比其他术语更通用(降序):属性-> 属性-> 类变量-> 字段。
以下段落摘自Grady Booch的“面向对象的分析与设计”,有助于阐明该主题。首先,了解状态的概念很重要:
对象的状态包括对象的所有(通常是静态的)属性加上每个属性的当前(通常是动态的)值。属性是指对象的属性和与其他对象的关系的总和。
OOP 在某些命名法方面非常通用,因为它因语言而异:
术语字段(Object Pascal)、实例变量(Smalltalk)、成员对象 (C++) 和插槽 (CLOS) 是可互换的,表示对象部分状态的存储库。它们共同构成了对象的结构。
但作者介绍的符号是准确的:
属性表示聚合对象的一部分,因此在分析和设计期间用于表示类的单一属性。使用与语言无关的语法,一个属性可以有一个名称、一个类,或两者兼有,还可以有一个默认表达式:
A:C=E
.类变量:类状态的一部分。一个类的类变量共同构成了它的结构。类变量由同一类的所有实例共享。在 C++ 中,类变量被声明为静态成员。
总之:
属性是一个广泛的概念,用于表示一个类的特定特征,包括它的属性以及它与其他类的关系。
属性 表示聚合对象的一部分,因此在分析和设计期间用于表示类的单一属性。
类变量是在一个存在单个副本的类中定义的属性,无论该类的实例存在多少。所以该类的所有实例共享它的值以及它的声明。
字段是实例变量的语言特定术语,即其值特定于每个对象的属性。
我从事 oop 已有 20 多年了,我发现人们经常对相同的事情使用不同的词。我的理解是字段、类变量和属性都意味着同样的事情。但是,您在问题中包含的 stackoverflow 链接最好地描述了属性。
通常,字段、方法、静态方法、属性、属性和类(或静态变量)不会因语言而改变......虽然语法可能会因每种语言而改变,但它们会以您期望的方式发挥作用跨语言(期望字段/数据成员等术语可以跨语言互换使用)
在 C# 中......
字段是存在于给定类实例的变量。
例如。
public class BaseClass
{
// This is a field that might be different in each instance of a class
private int _field;
// This is a property that accesses a field
protected int GetField
{
get
{
return _field;
}
}
}
字段具有“可见性”,这决定了其他类可以看到该字段,因此在上面的示例中,私有字段只能由包含它的类使用,但属性访问器提供子类对该字段的只读访问。
属性可以让您获取(有时称为访问器)或设置(有时称为 mutator)字段的值...属性让您可以做一些事情,例如防止从类外部写入字段,更改字段(例如私有/受保护/公共)。mutator 允许您在设置字段的值之前提供一些自定义逻辑
所以属性更像是获取/设置字段值的方法,但提供更多功能
例如。
public class BaseClass
{
// This is a field that might be different in each instance of a class
private int _field;
// This is a property that accesses a field, but since it's visibility
// is protected only subclasses will know about this property
// (and through it the field) - The field and property in this case
// will be hidden from other classes.
protected int GetField
{
// This is an accessor
get
{
return _field;
}
// This is a mutator
set
{
// This can perform some more logic
if (_field != value)
{
Console.WriteLine("The value of _field changed");
_field = value;
OnChanged; // Call some imaginary OnChange method
} else {
Console.WriteLine("The value of _field was not changed");
}
}
}
}
类或静态变量是类的所有实例都相同的变量。因此,例如,如果您想要一个类的描述,则该描述对于该类的所有实例都是相同的,并且可以通过以下方式访问使用类,例如。
public class BaseClass
{
// A static (or class variable) can be accessed from anywhere by writing
// BaseClass.DESCRIPTION
public static string DESCRIPTION = "BaseClass";
}
public class TestClass
{
public void Test()
{
string BaseClassDescription = BaseClass.DESCRIPTION;
}
}
在使用与属性相关的术语时,我会小心。在 C# 中,它是一个可以通过“装饰”类或方法来应用于其他类或方法的类,在其他上下文中,它可能只是指一个类包含的字段。
// The functionality of this attribute will be documented somewhere
[Test]
public class TestClass
{
[TestMethod]
public void TestMethod()
{
}
}
有些语言没有像 C# 那样的“属性”(见上文)
希望这一切都有意义......不想让你超载!
首先,您需要选择一种语言。例如,我建议您选择 Ruby 语言和社区。在您选择一种语言之前,您无法避免混淆,因为不同的社区对相同的事物使用不同的术语。
例如,Module
在 Ruby 中称为抽象类,Java 称为抽象类。在某些语言中称为属性instance variables
,在 Ruby 中称为属性。我特别推荐 Ruby,因为它具有逻辑性和设计良好的 OOP 系统。
在 *.rb 文件或irb(交互式 Ruby 解释器)的命令行中写入以下内容:
class Dog # <-- Here you define a class representing all dogs.
def breathe # <-- Here you teach your class a method: #breathe
puts "I'm breathing."
end
def speak # <-- Here you teach your class another method: #speak
puts "Bow wow!"
end
end
现在你有了一个类,你可以创建它的一个实例:
Seamus = Dog.new
您刚刚创建了一个实例,即 Dog 类的特定狗,并将其存储在常量 中Seamus
。现在你可以玩它了:
Seamus.breathe # <-- Invoking #breathe instance method of Seamus
#=> I'm breathing.
Seamus.speak # <-- Invoking #speak instance method of Seamus
#=> Bow wow!
至于您剩下的术语问题,“属性”或“属性”在 Ruby 中被理解为“变量”,几乎总是一个实例变量。至于“数据成员”这个词,就别管它了。术语“字段”在 Ruby 中并没有真正使用,而“类变量”在 Ruby 中意味着很少使用的东西,你现在绝对不需要知道。
因此,为了让世界保持美好并向您展示 OOP 在 Ruby 中非常简单和轻松,让我们创建一个属性,或者用 Ruby 术语来说,是一个Dog
类的实例变量。众所周知,每只狗都有一定的体重,不同的狗可能有不同的体重。因此,在创建新狗时,我们将要求用户告诉我们狗的重量:
class Dog
def initialize( weight ) # <-- Defining initialization method with one argument 'weight'
@weight = weight # <-- Setting the dog's attribute (instance variable)
end
attr_reader :weight # <-- Making the dog's weight attribute visible to the world.
end
Drooly = Dog.new( 16 ) # <-- Weight now must provide weight upon initialization.
Drooly.weight # <-- Now we can ask Drooly about his weight.
#=> 16
请记住,使用 Ruby(或 Python),事情很简单。
我在我的问题中发现.Net 中定义的属性只是代码的一种方便语法,它们根本不依赖于底层变量(当然,自动实现的属性除外)。因此,说“类属性和类字段之间有什么区别”就像说:方法和属性之间有什么区别。没有区别,一个是代码,一个是数据。而且,它们之间不需要有任何关系。
同一个词,比如“属性”和“财产”,在不同的语言和意识形态中被重复使用,具有截然不同的含义,这真是太糟糕了。也许有人需要定义一种面向对象的语言来谈论 OOP 中的概念?UML?
在课堂里
public class ClassSample
{
private int ClassAttribute;
public int Property
{
get { return ClassAttribute; }
set { ClassAttribute = value; }
}
}
在节目中
class Program
{
static void Main(string[] args)
{
var objectSample = new ClassSample();
//Get Object Property
var GetProperty = objectSample.Property;
}
}