从不同的类访问私有访问变量数据

Posted

技术标签:

【中文标题】从不同的类访问私有访问变量数据【英文标题】:Accessing private access variable data from different class 【发布时间】:2013-08-03 14:32:12 【问题描述】:

我的项目中有这个线程,它不断运行并接受新符号

public class StreamThread extends Thread 
    private Set<String> allSymbolSet = new HashSet<String>(Arrays.asList("USBC", "TCSD", "PCLJ"));
    private PriorityBlockingQueue<String> priorityBlocking = new PriorityBlockingQueue<String>();

    public void addSymbols(String str) 
        if (str != null) 
            priorityBlocking.add(str);
        
    

    public void run() 
        while (true) 
            try 
                while (priorityBlocking.peek() != null) 
                    String symbol = priorityBlocking.poll();
                    allSymbolSet.add(symbol);
                
             catch (Exception e) 
                e.printStackTrace();
            
        
    

我的问题是,我想从另一个类访问变量 allSymbolSet

从另一个类访问这个名为allSymbolSet 的变量的最佳方法是什么,为此我有两个选择

    将 allSymbolSet 的访问说明符从私有修改为默认。

    编写一个用于返回 Set 的 get 方法

请建议我,在这种情况下有什么好的方法??

【问题讨论】:

更有可能是2,但是为什么其他类尝试访问allSymbolSet,它想用它做什么? 【参考方案1】:

最好的方法是 getter 方法并同步对对象 allSymbolSet 的访问,如下所示:

public Set<String> getAllSymbolSet() 
    synchronized(allSymbolSet) 
        return allSymbolSet;
    

并在你的线程中同步对allSymbolSet的访问。

【讨论】:

非常感谢,但为什么我需要同步呢?在这种情况下是否需要同步?? 是的,因为你将有两个线程访问同一个 HashSet,HashSet 不是线程安全的 如果只想读取字段,真的需要同步吗? @AtishDipongkor 更好,因为在第一种情况下,您无法控制使用您的字段的内容,使用吸气剂您可以更好地控制如何共享您的对象。这种情况下需要同步访问 @NishantShreshth 是的,您需要同步才能阅读。或者考虑一个线程安全(er)实现***.com/questions/6992608/…【参考方案2】:

几个cmets:

如果您将设置设为非私有,则某些代码可能会修改它(错误地或故意地),这可能会导致 StreamThread 类中的行为不一致。不要那样做。 提供简单的 getter 并不能解决上述问题。最好退回您的套装副本。 在多线程环境中尽可能将变量设为最终变量 - 它解决了许多线程安全问题。 宁愿实现 Runnable 而不是扩展 Thread 您将需要同步对您的集合的所有访问(读取和写入),例如使用synchronizedSet,甚至更好地包装ConcurrentHashMap,这通常会提供更好的性能。 您可以在队列中简单地使用take 而不是peek+poll

所以你的最后一课可能是这样的:

public class StreamTask implements Runnable 

    private final Set<String> allSymbolSet;
    private final PriorityBlockingQueue<String> priorityBlocking = new PriorityBlockingQueue<String>();

    public StreamTask() 
         String[] symbols = "USBC", "TCSD", "PCLJ";
         //use a thread safe set, for example based on ConcurrentHashMap
         allSymbolSet = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean> ());
         Collections.addAll(allSymbolSet, symbols);
    

    public void addSymbols(String str) 
        if (str != null) 
            priorityBlocking.add(str);
        
    

    public Set<String> getSymbols() 
        return new HashSet<> (allSymbolSet); //return a copy
    

    public void run() 
        while (true) 
            try 
                allSymbolSet.add(priorityBlocking.take());
             catch (Exception e) 
                e.printStackTrace();
            
        
    

最后,我可能遗漏了一些东西,但该类看起来等同于更简单的:

public class StreamTask 

    private final Set<String> allSymbolSet;

    public StreamTask() 
         String[] symbols = "USBC", "TCSD", "PCLJ";
         //use a thread safe set, for example based on ConcurrentHashMap
         allSymbolSet = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean> ());
         Collections.addAll(allSymbolSet, symbols);
    

    public void addSymbols(String str) 
        if (str != null) 
            allSymbolSet.add(str);
        
    

    public Set<String> getSymbols() 
        return new HashSet<> (allSymbolSet); //return a copy
    

【讨论】:

+1 用于在返回 Set 时创建副本。很好的答案。 如果我使用 final 关键字,它会允许它修改 Set 和 PriorotyBlockingQueue 吗?? @Kiran 您可以添加到最终集或从中删除,但不能重新分配它。所以你不能写:allSymbolSet = new HashSet&lt;&gt;()建后。 非常感谢,还有一个问题,我正在以这种方式创建 allSymbolSet,public Set allSymbolSet= Collections.synchronizedSet(new HashSet,我还需要同步 getter 方法吗?? @Kiran 如果您像我建议的那样返回一个副本,那么是的,您需要同步,因为副本创建涉及需要手动同步的迭代。这就是为什么我建议在 ConcurrentHashMap 周围使用包装器的原因之一,它有一个线程安全的迭代器。【参考方案3】:

更好的方法是方法 2。编写一个 getter 方法。如果您想允许设置值,请稍后使用设置器。然后你的数据将被封装。

【讨论】:

【参考方案4】:

编写一个应该返回 Set 的 get 方法。通过使用它,您的 private 仍然是私有的,并且您还可以使用同一类的 Object 从外部访问它。

【讨论】:

以上是关于从不同的类访问私有访问变量数据的主要内容,如果未能解决你的问题,请参考以下文章

从测试访问私有变量并完成覆盖功能

如何访问其子类中的类的私有变量?

您可以在 Java 中访问私有变量,而无需来自非内部类的类的 getter [重复]

IntelliJ:更改变量列表的访问修饰符

为啥我不能从不同命名空间中的朋友类更改类的私有成员?

PHP访问控制