什么是在Java getter和setter方法的意义呢? [重复](What is the p

2019-07-19 00:57发布

这个问题已经在这里有一个答案:

  • 为什么要使用getter和setter /存取? [关闭] 38个答案

请原谅的长度,但这里有两个方案,无论是完全相同的,但一有,一个没有setter方法,getter方法和构造函数。

我已经采取了基本的C ++类之前,不要从它记住任何这些,而且目前我没有看到他们的时候,如果任何人都可以在拉门的术语解释他们我更欣赏它.. .AT的那一刻,他们似乎没有什么比浪费空间,使我的代码看起来更长更,但老师说,他们是重要的(到目前为止仅此而已)。

提前致谢! 而现在这里的代码:Mileage.java:

package gasMileage;

import java.util.Scanner; //program uses class Scanner

public class Mileage 
{
    public int restart;
    public double miles, gallons, totalMiles, totalGallons, milesPerGallon;
    public Mileage(int newRestart, double newMiles, double newGallons, 
                   double newTotalMiles, double newTotalGallons, double newMilesPerGallon)
    {
        setRestart(newRestart);
        setMiles(newMiles);
        setGallons(newGallons);
        setTotalMiles(newTotalMiles);
        setTotalGallons(newTotalGallons);
        setMilesPerGallon(newMilesPerGallon);
    }
    public void setRestart(int newRestart)
    {
        restart = newRestart;
    }
    public int getRestart()
    {
        return restart;
    }
    public void setMiles(double newMiles)
    {
        miles = newMiles;
    }
    public double getMiles()
    {
        return miles;
    }
    public void setGallons(double newGallons)
    {
        gallons = newGallons;
    }
    public double getGallons()
    {
        return gallons;
    }
    public void setTotalMiles(double newTotalMiles)
    {
        totalMiles = newTotalMiles;
    }
    public double getTotalMiles()
    {
        return totalMiles;
    }
    public void setTotalGallons(double newTotalGallons)
    {
        totalGallons = newTotalGallons;
    }
    public double getTotalGallons()
    {
        return totalGallons;
    }
    public void setMilesPerGallon(double newMilesPerGallon)
    {
        milesPerGallon = newMilesPerGallon;
    }
    public double getMilesPerGallon()
    {
        return milesPerGallon;
    }
    public void calculateMileage()
    {
        Scanner input = new Scanner(System.in);
        while(restart == 1)
        {
            System.out.print("Please input number of miles you drove: ");
            miles = input.nextDouble();
            totalMiles = totalMiles + miles;
            System.out.print("Please input number of gallons you used: ");
            gallons = input.nextDouble();
            totalGallons = totalGallons + gallons;
            milesPerGallon = miles / gallons;
            System.out.printf("Your mileage is %.2f MPG.\n", milesPerGallon);
            System.out.print("Would you like to try again? 1 for yes, 2 for no: ");
            restart = input.nextInt();
        }
        milesPerGallon = totalMiles / totalGallons;
        System.out.printf("Your total mileage for these trips is: %.2f.\nYour total gas consumed on these trips was: %.2f.\n", totalMiles, totalGallons);
        System.out.printf("Your total mileage for these trips is: %.2f MPG", milesPerGallon);
    }
}

Mileagetest.java:

package gasMileage;

public class Mileagetest 
{
    public static void main(String[] args) 
    {
        Mileage myMileage = new Mileage(1,0,0,0,0,0);
        myMileage.calculateMileage();
    }
}

现在对于一个没有getter和setter方法:

Testmileage.java:

package gasMileage;

import java.util.Scanner;

public class Testmileage 
{
    int restart = 1;
    double miles = 0, milesTotal = 0, gas = 0, gasTotal = 0, mpg = 0;
    Scanner input = new Scanner(System.in);
    public void testCalculate()
    {
        while(restart == 1)
        {
            System.out.print("Please input miles: ");
            miles = input.nextDouble();
            milesTotal = milesTotal + miles;
            System.out.print("Please input gas: ");
            gas = input.nextDouble();
            gasTotal = gasTotal + gas;
            mpg = miles/gas;
            System.out.printf("MPG: %.2f", mpg);
            System.out.print("\nContinue? 1 = yes, 2 = no: ");
            restart = input.nextInt();
        }
            mpg = milesTotal / gasTotal;
            System.out.printf("Total Miles: %.2f\nTotal Gallons: %.2f\nTotal MPG: %.2f\n", milesTotal, gasTotal, mpg);
    }
}

Testmileagetest.java:

package gasMileage;

public class Testmileagetest 
{

    /**
     * @param args
     */
    public static void main(String[] args) 
    {
        Testmileage test = new Testmileage();
        test.testCalculate();
    }

}

再次感谢!

Answer 1:

getter和setter的点, 无论何种语言的 ,是隐藏底层变量。 这使您可以尝试设置的值时添加验证逻辑 - 例如,如果你有一个字段,出生日期,你可能只想允许字段设置为在过去的一段时间。 这不能强制执行,如果该字段为公开访问和modifyable - 你需要的getter和setter方法。

即使你不需要任何验证的是,你可能需要它的未来。 编写getter和setter现在意味着接口保持一致,所以当你改变它现有的代码不会打破。



Answer 2:

其他答案通常给出一些理由使用getter和setter一个好主意,但我想给的,为什么他们是有用的有点完整的例子。

让我们举个例子,一个文件(无视存在File中的Java类)。 此File类有用于存储文件(.PDF,.EXE,.TXT等)的类型的字段......我们将忽略一切。

首先,您决定将其存储为一个String ,没有getter和setter方法:

public class File {
   // ...
   public String type;
   // ...
}

这里有一些问题,与不使用getter和setter。

满场的设置无法控制:

类的任何客户端可以做自己想做的事情是什么:

public void doSomething(File file) {
   // ...
   file.type = "this definitely isn't a normal file type";
   // ...
}

你以后决定,你可能不希望他们这样做......但因为它们在你的类直接访问现场,你有没有阻止它的方式。

不能很容易地改变内部表示:

再以后,你决定,你要的文件类型存储为称为接口的实例FileType ,可让您在不同的文件类型的一些行为相关联。 然而,你的类的许多客户都已经读取和设置文件类型为String秒。 所以,你有一个问题存在......你会伤了大量的代码(甚至在你无法自己解决,如果它是一个库中的其他项目的代码),如果你只是改变了字段从StringFileType

getter和setter如何解决这个问题

现在,假设你已经作出,而不是类型字段private和创建

public String getType() {
   return this.type;
}

public void setType(String type) {
   this.type = type;
}

控制设置该属性:

现在,当你想实现的要求,只有某些字符串是有效的文件类型,并防止其他字符串,你可以这样写:

public void setType(String type) {
   if(!isValidType(type)) {
       throw new IllegalArgumentException("Invalid file type: " + type);
   }
   this.type = type;
}

private boolean isValidType(String type) {
   // logic here
}

能够容易地改变内部表示:

改变String的类型的表示是比较容易的。 想象一下,你有一个enum ValidFileType它实现FileType ,并包含有效的文件类型。

你可以很容易地改变这样的类文件类型的内部表示:

public class File {
   // ...
   private FileType type;
   // ...
   public String getType() {
      return type.toString();
   }

   public void setType(String type) {
      FileType newType = ValidFileType.valueOf(type);

      if(newType == null) {
         throw new IllegalArgumentException("Invalid file type: " + type);
      }

      this.type = newType;
   }
}

由于类的客户一直在呼吁getType()setType()反正,没有从他们的角度变化。 只有类的内部改变,而不是其他类使用的接口。



Answer 3:

封装

存取方法(“getter和setter方法”),来掩饰有关如何在对象存储数据的详细信息。 在实践中,它们是存储和在面向非对象的方式检索数据美化了手段。 存取器不能有效地封装在任何有下列代码两段之间没有实际区别:

Person bob = new Person();
Colour hair = bob.getHairColour();
hair.setRed( 255 );

还有这个:

Person bob = new Person();
Colour hair = bob.hairColour;
hair.red = 255;

这两个代码片段暴露的想法,一个人是紧耦合的头发。 然后,该紧耦合揭示本身在整个代码库,造成脆的软件。 也就是说,它变得很难改变一个人的头发是如何存储。

代替:

Person bob = new Person();
bob.setHairColour( Colour.RED );

在此之前的前提下“说,不要问。” 换句话说,对象应指示(由其他对象)来执行特定的任务。 这是面向对象编程的整点。 很少人似乎得到它。

这两种情况的区别是这样的:

  • 在第一种情况下,鲍勃拥有超过什么颜色的头发会变得无法控制。 伟大的发型师与红发情有独钟,不那么伟大的鲍勃谁鄙视那种颜色。
  • 在第二种情况下,鲍勃拥有什么颜色的头发会变得因为在系统中没有其他物体被允许改变颜色而不Bob的权限完全控制。

为了避免这个问题的另一种方法是返回Bob的发色的副本(作为一个新的实例),因此不再连接到鲍勃。 我觉得这是一个不雅的解决方案,因为这意味着有行为另一个类的欲望,使用人的头发,即不再与人本身有关。 这降低了重用代码的能力,从而导致重复的代码。

隐藏数据类型

在Java中,不能有只有返回类型不同的两种方法签名,它真的不躲对象使用的基本数据类型。 你会很少,如果有的话,请参阅以下内容:

public class Person {
  private long hColour = 1024;

  public Colour getHairColour() {
    return new Colour( hColour & 255, hColour << 8 & 255, hColour << 16 & 255 );
  }
}

典型地,单个变量具有其数据类型通过使用相应的存取的逐字暴露,并且需要重构来改变它:

public class Person {
  private long hColour = 1024;

  public long getHairColour() {
    return hColour;
  }

  /** Cannot exist in Java: compile error. */
  public Colour getHairColour() {
    return new Colour( hColour & 255, hColour << 8 & 255, hColour<< 16 & 255 );
  }
}

虽然它提供了一个抽象级别,它是一个薄的面纱不执行任何对于松散耦合。

告诉,不要问

有关此方法的更多信息,请告诉,不要问 。

文件示例

考虑下面的代码,从ColinD的答案略作修改:

public class File {
   private String type = "";

   public String getType() {
      return this.type;
   }

   public void setType( String type ) {
      if( type = null ) {
        type = "";
      }

      this.type = type;
   }

   public boolean isValidType( String type ) {
      return getType().equalsIgnoreCase( type );
   }
}

该方法getType()在该实例中是多余的,不可避免地会(在实践中)导致复制的代码,例如:

public void arbitraryMethod( File file ) {
  if( file.getType() == "JPEG" ) {
    // Code.
  }
}

public void anotherArbitraryMethod( File file ) {
  if( file.getType() == "WP" ) {
    // Code.
  }
}

问题:

  • 数据类型。type属性不能容易地从字符串到整数(或另一个类)发生变化。
  • 默示协议。 这是耗时的抽象与具体的类型( PNGJPEGTIFFEPS )到一般( IMAGEDOCUMENTSPREADSHEET )。
  • 推出错误。 改变暗示协议将不生成编译器错误,这可能会导致错误。

完全避免问题通过防止请求数据的其他类:

public void arbitraryMethod( File file ) {
  if( file.isValidType( "JPEG" ) ) {
    // Code.
  }
}

这意味着改变get存取方法, private

public class File {
   public final static String TYPE_IMAGE = "IMAGE";

   private String type = "";

   private String getType() {
      return this.type;
   }

   public void setType( String type ) {
      if( type == null ) {
        type = "";
      }
      else if(
        type.equalsIgnoreCase( "JPEG" ) ||
        type.equalsIgnoreCase( "JPG" ) ||
        type.equalsIgnoreCase( "PNG" ) ) {
        type = File.TYPE_IMAGE;
      }

      this.type = type;
   }

   public boolean isValidType( String type ) {
      // Coerce the given type to a generic type.
      //
      File f = new File( this );
      f.setType( type );

      // Check if the generic type is valid.
      //
      return isValidGenericType( f.getType() );
   }
}

当系统中没有其他的代码将打破File类转换从具体类型(如JPEG)泛型类型(例如图像)的隐含协议。 系统中的所有代码必须使用isValidType方法,它不给类型调用对象,而是告诉 File类验证类型。



Answer 4:

我们的想法是,如果您的客户端类调用get / set函数,你可以改变后,他们做什么和呼叫者绝缘。 如果你有一个公共变量,我直接访问它,就没有办法了,当它被访问或设置您以后添加的行为。

即使在你的简单的例子,你可以利用它更有优势。

而不是使用:

milesPerGallon = miles / gallons;

在calculateMileage()

你可以改变setMiles()和setGallons()来更新milesPerGallon当他们被称为。 然后,删除setMilesPerGallon()来表示,这是一个只读属性。



Answer 5:

关键在于,一类不应该允许其字段的直接访问,因为这是实现特定的。 你可能想在以后更改类以使用其他数据存储,但保留类同它的“用户”,或者您可能希望创建一个接口,可以不包括任何领域。

看看在维基百科文章的主题。



Answer 6:

他们提供了一个公共接口为您的类和封装的一些措施。 考虑一下如何去访问公共数据,而getter和setter。

Mileage m = new Mileage();
m.miles = 5.0;
m.gallons = 10.0;
...

现在,如果你决定要一些验证添加到您的类,你要到处更改代码的字段直接访问。 如果你只是使用getter和setter从一开始( 只需要在那里 ),就可以避免这一努力,并只在一个地方更改代码。



Answer 7:

使用getter和setter让您灵活后来改变实现。 你也许不认为你需要的,但有时你做的。 例如,您可能需要使用代理模式,以延迟加载的对象,它是使用昂贵的:

class ExpensiveObject {
    private int foo;

    public ExpensiveObject() {
       // Does something that takes a long time.
    }

    public int getFoo() { return foo; }
    public void setFoo(int i) { foo = i; }
}

class ExpensiveObjectProxy extends ExpensiveObject {
    private ExpensiveObject realObject;

    public ExpensiveObjectProxy() { ; }

    protected void Load() {
       if ( realObject == null ) realObject = new ExpensiveObject();
    }

    public int getFoo() { Load(); return realObject.getFoo(); }
    public void setFoo(int i) { Load(); realObject.setFoo(i); }
}

class Main {
    public static void main( string[] args ) {
         // This takes no time, since ExpensiveOjbect is not constructed yet.
         ExpensiveObject myObj = new ExpensiveObjectProxy();

         // ExpensiveObject is actually constructed here, when you first use it.
         int i = myObj.getFoo();
    }
}

如果这往往涉及到玩的是当你有通过ORM映射到数据库中的对象。 你只加载你需要的东西,然后再返回到数据库中,如果/当实际使用它来装载其余部分。



Answer 8:

一般来说getter和setter方法是一个糟糕的黑客在早期的GUI构建器(Borland公司)要解决的事实,所有的变量应该是私有的(真的,这是绝对必要的)

有些人把他们的抽象,但事实并非如此。 一个样板制定者/吸气只不过是一个公共成员更好。 他们仍然可以充分地在次类无法控制,还是限制类的变化(如果你的变量是一个int,你仍然可以更改调用setter和getter一切的变量更改为一个字符串变量)

getter和setter鼓励类的外部访问类的数据。 访问类的成员的任何代码应在该类中可能存在(如您的设计状态),因此不应该需要制定者或干将。 他们应该是不必要的。

也迫使二传手到所有的类是可怕的,这意味着你的类根本不可能是一成不变的,而你应该确实有一个很好的理由使一个类可变的。

这就是说,它们是一种跨领域的关注一样持久性引擎和GUI建设者在那里他们可以获取和设置值和类可以监视什么了或改变,修改或验证它是有用的。

对于那些需要交叉可变访问系统更好的图案。将直接通过反射访问变量BUT调用setter或getter如果存在 - 使设定器和如果可能的话私人吸气剂。

这将允许非面向对象的跨部门代码才能正常工作,可以让你的类修改设置和获取时,它需要和允许吸气剂(有时真正有用的)必要。



Answer 9:

存取方法点IE浏览器。 getter和setter方法是提供封装AKA信息隐藏。 这是面向对象编程的基本原则之一。

存取方法

信息隐藏/封装



Answer 10:

用一个词来回答是接口

接口允许方法,没有田,所以成规是有此目的的getX和setX的方法。

(和接口是从Java中实现分离功能的方式)



Answer 11:

你举的例子是极端荒谬的地步。 是的,所有的getter和setter臃肿的代码,在这种情况下,增加价值。 但是封装的基本思想是为许多相互作用的部件,而不是小的,独立的程序组成更大的系统。

的getter和setter方法是有用的,明智的用途特点:

  • 所使用的许多其他类A类(隐藏实现细节使得它更容易为客户)
  • 只为它们实际上是需要哪些字段getter和setter方法 - 尽可能少的,大多数字段应该是私有的,只有自己的类中使用
  • 一般很少setter方法:可变域使它更难跟踪程序的状态不是只读字段
  • getter和setter,实际上的东西,除了访问田间,如抛出无效值异常或制定者更新“最后修改”时间戳,或吸气,计算在飞行的值,而不是依赖于底层的场


Answer 12:

一晃几个月。 也许你的老师要求你实现Milage类的远程版本。 也许作为一个Web服务,也许别的东西。

如果没有的getter / setter方法,你就必须处处改变每代码acccesses一个Milage,用的getter / setter方法你很可能(在一个完美的世界ATLEAST)只需要改变一个Milage类型的创建。



Answer 13:

getter和setter允许您构建有用的快捷键为对象中访问和变异数据。 一般来说,这可以看作是一种替代具有与用于获取和设置的值,象这样的对象两个功能:

{
    getValue: function(){
        return this._value;
    },
    setValue: function(val){
        this._value = val;
    }
}

最明显的优势,以这种方式编写JavaScript是,你可以使用它,你不想直接访问用户晦涩值。 最后的结果看起来像以下(使用闭包来存储新建字段的值):

function Field(val){
    var value = val;

    this.getValue = function(){
        return value;
    };

    this.setValue = function(val){
        value = val;
    };
}

添加setter和getter方法,使管理bean的状态访问,你需要添加setter和getter方法为该状态。 该createSalutation方法调用bean'sgreet方法,以及getSalutation方法检索结果。 一旦setter和getter方法已被添加,豆是完整的。 最终的代码如下所示:包问候;

import javax.inject.Inject;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class Printer {

    @Inject @Informal Greeting greeting;

    private String name;
    private String salutation;

    public void createSalutation() {
        this.salutation = greeting.greet(name);
    }

    public String getSalutation() {
        return salutation;
    }
    public String setName(String name) {
       this.name = name;
    }

    public String getName() {
       return name;
    }
}


Answer 14:

封装代码重用能力是面向对象的编程之美。 如果我们处理的是在我们的代码中的一些敏感数据,那么我们将它声明为私有数据域,即我们封装我们的数据,使任何人都可以访问它directly.Now谁想要访问这些数据字段必须利用getter和setter方法中的任何一个即受控访问机制来处理敏感数据的字段。 下面的例子可以理解的优势和setter和getter方法的重要性有所帮助。

  • 我已经实现其中我正在利用天变量的类。
  • 在我的课没有人可以设置的天值超过365。
  • 有些人想从我的类继承。(代码重用性)。
  • 现在,当他进入天的值超过365,那么我的类的所有功能将失败。
  • 因此,我应该申报的日期为私有数据字段变量。
  • 私人现在,如果我宣布天的数据字段,则没有人可以设置多天,然后365的价值,我会实现一个setter函数有关输入不受上述限制。


文章来源: What is the point of setters and getters in java? [duplicate]