Java 使用getter和setter具有私有属性的优势是什么?
在面向对象编程中,我曾经有过这个问题,现在仍然有: 如果我们 将为其创建一个公共getter和一个公共setter 在安全级别上,我看不到上述情况与将类成员声明为公共的情况之间有任何区别Java 使用getter和setter具有私有属性的优势是什么?,java,c++,oop,Java,C++,Oop,在面向对象编程中,我曾经有过这个问题,现在仍然有: 如果我们 将为其创建一个公共getter和一个公共setter 在安全级别上,我看不到上述情况与将类成员声明为公共的情况之间有任何区别 谢谢 封装提供了数据隐藏和对成员变量的更多控制。如果一个属性是公共的,那么任何人都可以访问它,并且可以为它指定任何值。但是如果您的成员变量是私有的,并且您已经为它提供了一个setter。然后,您总是可以选择在setter方法中进行一些约束检查,以避免设置不合逻辑的值 例如,仅包含公共成员的类: class My
谢谢 封装提供了数据隐藏和对成员变量的更多控制。如果一个属性是公共的,那么任何人都可以访问它,并且可以为它指定任何值。但是如果您的成员变量是私有的,并且您已经为它提供了一个setter。然后,您总是可以选择在setter方法中进行一些约束检查,以避免设置不合逻辑的值 例如,仅包含公共成员的类:
class MyClass {
public int age;
}
public MyClassUser {
public static void main(String args[]) {
MyClass obj = new MyClass();
obj.age = -5 // not a logical value for age
}
}
具有私有成员和setter的同一类:
class MyClass {
private int age;
public void setAge(int age) {
if(age < 0) {
// do not use input value and use default
} else {
this.age = age;
}
}
}
class-MyClass{
私人互联网;
公共无效设置(整数){
如果(年龄<0){
//不要使用输入值,而使用默认值
}否则{
这个。年龄=年龄;
}
}
}
您可以稍后更改类成员的内部表示,将函数添加到GETER和SETER(例如通知观察者),而不改变接口(公共吸气剂和SETER)。
在封装的旁边,考虑SET不是简单设置值的情况。
如果你在很多课堂上使用它呢?现在你意识到你想改变它的功能了?您必须在手动设置的整个位置进行更改。然而,如果你有一个setter,生活会更轻松。访问器方法为给定字段提供一个单点更新。这是有益的,因为验证逻辑或对字段的其他修改可以通过单个方法进行控制,而不是在整个代码库中直接访问字段 请参阅此IBM文档,其中详细介绍了更多好处: 在安全级别上,我看不到上述情况与将类成员声明为公共的情况之间有任何区别 眼前的问题是: 1) 如果要在设置值时检查某些条件,该怎么办 2) 如果子类希望通过ovveridng方法返回或设置其他内容,该怎么办
其他原因:如果公共getter和公共setter只是返回私有属性的值并更改其值,那么我看不出有什么区别 但是,您正在实现封装,因此稍后您可以实现不同的行为,例如,包括setter或write-only/read-only属性的参数检查
class-Foo{
private int age=-1;//未设置值
公共设置(INTA){
if(a<0){
抛出新的IllegalArgumentException(“无效年龄”+a);
}
年龄=a;
}
公众假期(){
如果(年龄<0){
抛出新的InvalidStateException(“以前未设置年龄”)
}
回归年龄;
}
}
简而言之:您获得了控制权,可以确保值是正确的。这叫做封装。事实上,如果你在一个小项目上独自开发,你不会重用你的代码,这有点没用,但它基本上是一种好习惯 但是,在团队开发中,您可能需要对修改进行一些控制,您可以通过getter和setter来完成
此外,在某些类中,只有getter,因为setter将由构造函数或其他函数完成。将变量声明为
private
在Java中称为封装
在用Java或任何面向对象编程语言编写代码时,使用封装有以下几个优点:
封装的代码更加灵活,易于根据新的需求进行更改
Java中的封装使单元测试变得容易
Java中的封装允许您控制谁可以访问什么
封装还有助于用Java编写不可变类,这在多线程中是一个不错的选择
环境
封装减少了模块之间的耦合,并增加了模块内部的内聚性,因为所有模块都是一件事
封装在一个地方
封装允许您在不影响代码其他部分的情况下更改代码的一部分李>
另一个优势是
在java中使变量私有,并为它们提供getter和setter,使您的类与JavaBean命名约定兼容
如果您有一个范围有限的数据传输对象,并且按照设计,它应该没有与其关联的逻辑,那么我在getter和setter中看不到任何值
但是,如果您有一个组件,该组件可能与逻辑相关,也可能与逻辑无关,或者可以广泛使用,那么隐藏数据存储方式的详细信息是有意义的。起初,看起来所有的getter和setter都很琐碎,只是填满了您的类,但随着时间的推移,您可能会向setter添加验证,甚至更改getter。e、 g.您可能会删除一个字段(并在将来返回一个常量)、将数据存储在委托对象中或从其他字段计算值。您的问题确实是字段和属性之间的区别。文件通常是私有的,属性会公开它们。贝娄引用了一个精彩的答案:
属性公开字段。字段应该(几乎总是)保留
专用于类,并通过get和set属性访问。性质
提供一个抽象级别,允许您在
不影响外部事物访问它们的方式
利用你的课堂
在C#中,自动属性将为您创建一个字段,而无需手动
class Foo {
private int age = -1; // unset value
public setAge(int a) {
if (a < 0) {
throw new IllegalArgumentException("Invalid age "+a);
}
age = a;
}
public getAge() {
if (age < 0) {
throw new InvalidStateException("Age was not previously set.")
}
return age;
}
}
public Prop { get; set; }
public Prop { public get; private set; }
public Prop { private get; public set; }
// etc, you can specify access modifier as per your need
class Person //version 1.0
{
std::string name;
public:
std::string getName() const { return name; }
void setName(const std::string &newName)
{
if (!newName.empty()) //disallow empty names
name = newName;
}
};
class Person //version 1.1
{
std::string firstName;
std::string lastName;
public:
std::string getFirstName() const { return firstName; }
void setFirstName(const std::string &newFirstName)
{
firstName = newFirstName;
}
std::string getLastName() const { return lastName; }
void setLastName(const std::string &newLastName)
{
if (!newLastName.empty()) //disallow empty last names
firstName = newFirstName;
}
std::string getName() const
{
std::ostringstream s;
if (!firstName.empty())
s << fistName << ' ';
s << lastName;
return s.str();
}
void setName(const std::string &newName)
{
setFirstName(splitUntilLastSpace(newName));
setLastName(splitFromLastSpace(newName));
}
};
class Angle
{
public:
void Set(MyAngleTypedef a_value) { m_angle = a_value; }
// Note the 'Radians' type
void SetRadians(Radians a_value) { m_angle = ConvertRadiansToOurUnit(a_value); }
// Note the 'Degrees' type
void SetDegrees(Degrees a_value) { m_angle = ConvertDegreesToOurUnit(a_value); }
void Get(MyAngleTypedef a_value) const { return m_angle; }
// Note the 'Radians' type
Radians GetRadians(Radians a_value) const { return ConvertOurUnitToRadians(m_angle); }
// Note the 'Degrees' type
Degrees GetDegrees(Degrees a_value) const { return ConvertOurUnitToDegrees(m_angle); }
private:
// Raw value of the angle in some user-defined scale.
MyAngleTypedef m_angle;
}