【问题标题】:Java Encapsulation Concept not clearJava封装概念不清楚
【发布时间】:2013-09-27 06:47:35
【问题描述】:

这是基本问题,但我仍然不了解封装概念。我不明白我们如何从其他类中更改类的属性。因为无论何时 我们尝试设置类的公共实例值,我们必须创建该类的对象,然后设置值。每个对象引用不同的内存。所以即使我们改变 这不会影响任何其他对象的实例值。

即使我尝试使用静态公共实例值进行更改,我也无法更改类属性值。

示例如下

// Employee class
public class Employee {
    public static int empid;
    public static String empname;

    public static void main(String[] args) {
        System.out.println("print employe details:"+empid+" "+empname);
    }

    // EmployeeTest  class
    public class EmployeeTest {

        public static void main(String[] args) {
            Employee e = new Employee();
            e.empid=20;
            e.empname="jerry";
            Employee.empid=10;
            Employee.empname="tom";
        }

    }
}

每次我运行 Employee 类时,我都会得到相同的值

print employe details:0 null

即使我没有遵循封装概念,也无法更改员工类的公共实例值。请帮助我理解我出错的概念。

【问题讨论】:

    标签: java encapsulation


    【解决方案1】:

    是的,这有时会有点令人困惑。让我们一步一步来:首先,你需要了解

    • 什么是封装,为什么使用它?

    封装是四个OOP 基本概念之一。封装是将类中的字段设为私有并通过公共方法提供对字段的访问的技术。如果一个字段被声明为私有的,它不能被类外的任何人访问,从而隐藏了类中的字段。因此,封装也称为数据隐藏。

    封装可以描述为一种保护屏障,防止代码和数据被类外定义的其他代码随机访问。对数据和代码的访问由接口严格控制。

    封装的主要好处是能够在不破坏使用我们代码的其他人的代码的情况下修改我们实现的代码。借助此功能封装为我们的代码提供了可维护性、灵活性和可扩展性

    举个小例子:

    public class EncapTest{
    
       private String name;
       private String idNum;
       private int age;
    
       public int getAge(){
          return age;
       }
    
       public String getName(){
          return name;
       }
    
       public String getIdNum(){
          return idNum;
       }
    
       public void setAge( int newAge){
          age = newAge;
       }
    
       public void setName(String newName){
          name = newName;
       }
    
       public void setIdNum( String newId){
          idNum = newId;
       }
    }
    

    上述方法称为访问器(又名 getter 和 setter)。现在你可能会问,

    • 为什么要使用访问器..? 实际上有很多充分的理由考虑使用访问器而不是直接公开类的字段。Getter 和 Setter 使 API 更加稳定。

    例如,考虑一个类中的公共字段可供其他类访问。现在稍后,您想在获取和设置变量时添加任何额外的逻辑。这将影响使用 API 的现有客户端。因此,对这个公共字段的任何更改都需要更改引用它的每个类。相反,使用访问器方法,可以很容易地添加一些逻辑,比如缓存一些数据,稍后再懒惰地初始化它。此外,如果新值与以前的值不同,则可以触发属性更改事件。所有这些对于使用访问器方法获取值的类来说都是无缝的。

    关于它们是什么以及它们是什么的教程和解释太多了。谷歌他们。

    至于您当前的问题:

    1. 你有两个不同的类,每个都有一个主类。那是错的。它们将具有不同的属性。
    2. @Subhrajyoti Majumder 建议的代码更改是正确的。检查答案以解决问题。

    与此同时,请继续阅读

    为了更好地理解这些概念。希望能帮助到你。 :)

    【讨论】:

    • 感谢您的回复,这对您很有帮助,您能否给我举个例子:封装没有实现以及它会产生怎样的影响?
    • @Zeeshan 已经给出了解释。他的解释非常干净。 :)
    【解决方案2】:

    您似乎分别运行了两个不同的类,并假设您在运行EmployeeTest 时对属性所做的更改将反映在Employee 运行中。请注意,更改将反映在同一个 JRE 实例中。如果我误解了您的问题,请见谅。

    编辑:根据用户输入。以下是如何访问和更新静态成员值的代码:

    class Employee {
        public static int empid;
        public static String empname;
    
        public static void main(String[] args) {
            System.out.println("print employe details:" + empid + " " + empname);
        }
    }
    
    // EmployeeTest class
    public class EmployeeTest {
    
        public static void main(String[] args) {
            Employee e = new Employee();
            e.empid = 20;
            e.empname = "jerry";
            Employee.empid = 10;
            Employee.empname = "tom";
            Employee.main(null);
        }
    
    }
    

    【讨论】:

    • 感谢您的回复。您能否举个例子,如果我们不实现封装概念,如何更改实例值。在我上面的示例 Employee 类中,我们如何更改实例值。如果我们不实现封装它如何影响员工类在这两种情况下无论我们实现封装还是不实现封装都一样。
    • @JunedAhsan 你能告诉Employee.main(null);在你上面的代码中做什么吗?
    【解决方案3】:

    public static 字段关联的是类而不是对象,它破坏了对象的封装规则。

    Employee 类有两个封装字段empid & empname

    public class Employee {
        private int empid;
        private String empname;
    
        public int getEmpid(){
            return this.empid;
        } 
        public void setEmpid(int empid){
            this.empid = empid;
        }
        ...
    }
    
    public class EmployeeTest {
          public static void main(String[] args) {
                Employee e = new Employee();
                e.setempId(1);
                Employee e1 = new Employee();
                e1.setempId(2);
          }
    }
    

    Documentation for better understanding on encapsulation

    【讨论】:

    • static 如何打破封装?将成员变量声明为public 违反了封装,但为什么static 一般会违反呢?
    • static 打破了封装规则,因为可以直接访问它而无需设置器或获取器。如果您声明这样的变量:public staticstatic,当从另一个类调用它时,您可以编写:object.variable = value;
    【解决方案4】:

    封装可以描述为一个保护屏障,防止代码和数据被类外定义的其他代码随机访问。 对数据和代码的访问由界面严格控制。

    Java 中的封装是一种将类中的字段设为私有并通过公共方法提供对字段的访问的技术。

    如果一个字段被声明为私有,则该类之外的任何人都不能访问它, 从而隐藏类中的字段。因此,封装也称为数据隐藏

    实时示例:汽车和车主。汽车的所有功能都与车主一起封装。因此,没有其他人可以访问它..

    下面是这个例子的代码。

    public class Main {
    
      public static void main(String[] args) {
        Owner o1=new Car("SONY","Google Maps");
        o1.activate_Sunroof();
        o1.getNavigationSystem();
        o1.getRadioSytem();
     }
    }  
    //Interface designed for exposing car functionalities that an owner can use.
    public interface Owner {
         void getNavigationSystem();
         void getRadioSytem();
         void activate_Sunroof();
    }
    /*
    Car class protects the code and data access from outside world access by implementing Owner interface(i.e, exposing Cars functionalities) and restricting data access via private access modifier.
    */
    public class Car implements Owner {
                    private String radioSystem;
                    private String gps;
    
                    public Car(String radioSystem, String gps) {
                        super();
                        this.radioSystem = radioSystem;
                        this.gps = gps;
                    }
    
                    public String getRadioSystem() {
                        return radioSystem;
                    }
    
                    public void setRadioSystem(String radioSystem) {
                        this.radioSystem = radioSystem;
                    }
    
                    public String getGps() {
                        return gps;
                    }
    
                    public void setGps(String gps) {
                        this.gps = gps;
                    }
    
                    @Override
                    public void getNavigationSystem() {
                        System.out.println("GPS system " + getGps() + " is in use...");
                    }
    
                    @Override
                    public void getRadioSytem() {
                        System.out.println("Radio system " + getRadioSystem() + " activated");
                    }
    
                    @Override
                    public void activate_Sunroof() {
                        System.out.println("Sunroof activated");
                    }
    }
    

    【讨论】:

    • 通过提供公共设置器不是将实体细节暴露给外界吗?最终打败了封装的全部目的?我们如何才能使其受到严格控制?
    【解决方案5】:

    封装的概念是一种与信息隐藏相关的设计技术。基本原则是通过精心设计的接口提供对类属性的受保护访问。封装的目的是强制类的不变量。

    按照你的例子考虑这个类的接口:

    class Employee
    
      private final String firstName;
      private final String lastName;    
    
      public Employee(final firstName, final lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
      }
    
      public String getName() {
        return firstName + " " + lastName;
      }
    }
    

    请注意,通过将属性声明为私有,此类会限制客户端直接访问员工对象实例的状态。客户端访问它们的唯一方法是通过 getName() 方法。这意味着这些属性被类封装。另请注意,通过将属性声明为 final 并在构造函数中对其进行初始化,我们创建了一个有效的不可变类,即其状态在构造后无法修改。

    另一种实现方式如下:

    class Employee
    
      private String firstName;
      private String lastName;    
    
      public Employee(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
      }
    
      public String getName() {
        return firstName + " " + lastName;
      }
    
      public String setName(String firstName, String lastName) {
    
        if (firstName == null) {
          throw new IllegalArgumentException("First name cannot be null");
        }
    
        if (lastName == null) {
          throw new IllegalArgumentException("Last name cannot be null");
        }
    
        this.firstName = firstName;
        this.lastName = lastName;
      }
    }
    

    在这个例子中,对象不是不可变的,但它的状态是被封装的,因为访问它只能通过访问器和修饰符进行。请注意,封装如何帮助您保护对象状态的不变量。通过一种方法约束修改,您可以更好地控制对象状态的修改方式,添加验证以确保任何修改都符合类的规范。

    【讨论】:

      【解决方案6】:
      Encapsulation means combining data and code together(class). The main purpose of encapsulation is you would have full control on data by using the code.
      
      class Encap{
      
      private int amount;
      
      public void setAmount(int amount)
      {
      this.amount = amount;
      }
      
      Here, you can set the amount using the setAmount method, but value should be more than 100. So, i have the control on it.
      
      public void setAmount(int amount)
      {
      if(amount>100)
      this.amount = amount;
      }
      

      【讨论】:

        【解决方案7】:

        封装 =VARIABLES(let private a,b,c)+ METHODS(setA&getA,setB&getB....) 我们可以使用 private 修饰符进行封装。 让我们考虑一下您在班级中创建的一个公共变量和一个私有变量... 如果您必须将这些变量提供给另一个类以只读方式(只有他们可以看到和使用无法修改),则公共变量或方法不可能,但我们可以通过提供 get 私下做到这一点方法。 所以你的类私有变量或方法在你的控制之下。但在公共场合没有机会......我想你可以理解。

        【讨论】:

          【解决方案8】:

          当然,对一个对象的更改不会影响另一个对象。假设您有一个班级学生,并且您学校的所有孩子都是它的对象。如果一个人离开学校,这并不意味着其他所有学生(学生班级的对象)也应该离开学校。

          封装是将您的类变量设为私有的概念,这样任何人都无法直接从外部世界中使用您的数据成员。但是您提供 public 方法,让外部世界以您希望的方式与您的数据成员一起玩。上面的 Subhrajyoti Majumder 给出了很好的封装编码示例。

          (类的所有对象的静态成员都是相同的。例如:静态计数变量,用于统计学生类对象的数量。(在校学生数))。

          按照您的要求进行编辑:

          例子:

          public class student{
              public String name;
              public student() {}
           }
          

          在您的主要功能中,外部世界可以使用您的类属性:

          student s = new student();
          s.name = "xyz";
          

          假设,你不想让外部世界改变你对象的 name 属性。那么你应该将名称'name'设为私有,并提供一个仅查看名称(get)的公共方法。

          例子:

          public class student{
              private String name;
              public student() {}
              public String getName(){
                return this.name;
                }
           }
          

          现在在您的 main 方法中,您只能获取名称对象,而不能将其设置为新值,就像您在第一个示例中所做的那样。

          student s = new student();
          String sname = s.getName();
          

          如果你尝试:

          s.name = "newname";
          

          编译器不允许你这样做。因为您没有访问私有成员的权限。

          【讨论】:

          • 谢谢各位,能否请您提供带封装和不带封装的示例类,以及两种情况下的结果有何不同。我的意思是我想看看两种实现中的 o/p 差异。跨度>
          • @user2693404 我已经用示例编辑了答案。现在有帮助吗?你明白这个概念了吗?有什么问题吗?
          • 学生 s = new student(); s.name = "xyz";此更改仅针对对象的权限,更改不在类级别,它不会影响任何其他对象权限。那么封装对我们有何用处?this s.name = "xyz";只会影响 object 不会影响任何其他对象。
          • @user2693404 请阅读我回答的第二段。封装与它是否会影响唯一的“s”对象或每个创建的对象无关。封装是一种技术,在我的回答的第二段中提到了它,最后给出了它的例子。就变化的影响而言,我最后还提到,对于每个创建的学生类对象,只有 static 类型的变量是相同的。想象一下这种情况,您想计算创建的学生对象的数量。还有其他问题吗?
          【解决方案9】:

          运行 Employee 类时得到输出“print employee details:0 null”的原因是这些变量没有初始化。也就是说,您不会在 Employee 类中为它们分配任何值。

          无论您在 EmployeeTest 类中做什么,都不会影响 Employee 下次运行时的变量值。将 Java 程序的每次运行视为“白板”。

          在封装方面,您真的不应该使用static 关键字。如果您要进行封装,请查看此问题的其他答案,它有一个很好的代码示例供您使用。

          【讨论】:

            【解决方案10】:

            封装是一个面向对象的概念。 该类被认为是一个包含数据+行为的胶囊。 数据应该是私有的,并且只能使用称为 getter 和 setter 的公共方法访问。 您可以查看此encapsulation 教程以获取有关此概念的更多信息。

            【讨论】:

              【解决方案11】:

              ENCAPSULATION 是将方法和变量包装为一个单元的机制。例如胶囊,即几种药物的混合。

              一个类的变量将被其他类隐藏,因为它将被声明为私有,并且只能通过其当前类的方法访问

              在 Java 中实现封装 - * 将类的变量声明为私有。 * 提供公共的setter和getter方法来修改和查看变量值。 * Java Bean类是完全封装类的例子。

              【讨论】:

                【解决方案12】:

                你的意思是说empid的值应该是10和empname tom而不是0和null, 如果是那么-:

                1) 变量的内存是在运行时分配的,在程序终止后也会被释放。

                2)因此,如果您认为一旦给 empid 10 它应该始终为 10,那么事实并非如此,因为 empid 只是对存储“10”的内存的引用。

                3)所以通过释放,我的意思是 empid 在程序终止后不再指向存储 10 的内存区域

                4) 每当您执行一个新程序时,empid 现在指向其他内存区域,并且该内存根据各自的数据类型分配默认值,以防静态变量。 因此总是 0 和 null。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2020-08-22
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-01-27
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-06-29
                  • 2018-09-20
                  相关资源
                  最近更新 更多