我应该使用静态还是getter / setter?

时间:2015-10-23 08:03:23

标签: java android arrays variables static

我正在android中创建一个小型的musicplayer应用程序,其中我的主要活动是使用许多这样的静态变量: -

 public class Fragmentactivity extends FragmentActivity {

         static ArrayList<String> s3=new ArrayList<String>();
        static ArrayList<String> s5=new ArrayList<String>();
        static ArrayList<String> songpaths=new ArrayList<String>();
         static ArrayList<String> alldirectorypaths=new ArrayList<String>();
         static ArrayList<String> internalpaths=new ArrayList<String>();
         static ArrayList<String> tempsongnames=new ArrayList<String>();
         static ArrayList<Bitmap> thumbnails=new ArrayList<Bitmap>();
         static int internal=0;
         static ArrayList<String> folderpaths=new ArrayList<String>();
    //my addtional code after it
    }

我正在其他课程中访问它,如: -

  public class A{
    Fragmentactivity.songpaths.get(index);
    //and in  many other classes also i used it

我在大多数课程中到处都有很多静态变量 但现在我了解到这不是开发的好习惯。

我应该继续使用静态还是应该使用getter / setter?

或者,如果有其他方法可以重复使用变量......请建议我。

任何帮助将不胜感激:)

提前致谢:)

9 个答案:

答案 0 :(得分:8)

我不是Android专家。 static具有特殊含义,可以在所有实例之间共享它们。

因此,如果你打算在它们的多个实例之间分享它们,那就用当前的方式进行预测。

  

我应该继续使用静态还是应该使用getter / setter?

假设您想要共享变量,我会将它们混合

Fragmentactivity.getSongNames().get(index);

更新:

如果你没有对它进行多次讨论,只需摆脱静态并为其提供getter和setter。这就是你所需要的一切。

public class Fragmentactivity extends FragmentActivity {

     private ArrayList<String> s3=new ArrayList<String>();

   ...
   ...
    public ArrayList<String> getS3() {
    return this.s3;
   }

   public setS3(ArrayList<String> input){
   this.s3= input;
  }

...

答案 1 :(得分:4)

在数据模型的设计中(在使用静态访问变量的上下文中)要回答的主要问题是 - 此变量是否与类相关联(如果是这样,那么我们使用static modifier)或者使用这个类的具体实例(然后这个变量应该是非静态的)。

以下是关于在Java中使用静态变量的优点和缺点的大量帖子(link1link2link3)。此信息也与Android相关。还有一些事情需要在Android上提及:

  • 严格来说recommended是为了避免创建对Context及其任何子类的静态引用,因为这是内存泄漏的直接来源;
  • 虽然静态变量与具体对象没有关联,但它们不会被垃圾收集,但是当应用程序进程被杀死时(操作系统或用户),它们的值仍将被清除。因此,它不适合长期存储有价值的数据。

关于静态访问数据的可能替代方案,以下是最常用的方法:

  1. 单身人士模式。最简单的方法之一(来自通常的Java):

    public class GlobalStorage {
        private static volatile GlobalStorage instance; // and drumroll - here we use static access again to make this data accessible everywhere in the app
        private GlobalStorage() { }
    
        public static GlobalStorage getInstance() {
            if (instance == null ) {
                synchronized (GlobalStorage.class) {
                    if (instance == null) {
                        instance = new GlobalStorage();
                    }
                }
            }
    
            return instance;
        }
    }
    
  2. Application类的用法。 创建一个子类Application

    的类
    public class CustomApp extends Application{
    private Storage mStorage;
    
         @Override
         public void onCreate() {
             super.onCreate();
    
             mStorage = new Storage();
         }
    
         public Storage getStorage(){
             return this.mStorage;
         }
    }
    

    并将其作为<application>标记的属性

    在Manifest中注册
    <application
       android:name=".CustomApp"
       .... />
    
  3. 虽然这种方法是框架定义的,但它也不是“银弹”。直接从documentation

      

    通常不需要子类Application。在大多数情况下,   静态单例可以在更模块化的情况下提供相同的功能   办法。如果您的单身人士需要全局上下文(例如注册   广播接收器),可以给出一个检索它的功能   内部使用Context.getApplicationContext()的Context   首先构建单身人士。

答案 2 :(得分:3)

如果您想要传达2个碎片/活动,请使用Bundle

答案 3 :(得分:3)

它或多或少取决于您希望实现的功能。就像你想要在实例之间共享这些变量一样。使用getter setters与声明变量static无关。对于任何类型的变量,您都可以使用getters and setters

除了访问者/变异者之外,他们还有其他优势。

  

通常声明getter会阻止你的变量(esp mutable)暴露给外部世界。

     

如果您不希望您的客户直接更新您的变量,那么Setter会很有帮助。

例如,考虑日期变量的情况

  

对于date类型变量,您可能希望将日期变量的副本返回给客户端,而不是您自己的引用。因为客户端可能会滥用此引用或损坏它。   在调用setter时,您可能希望先检查日期或其格式的有效性。

答案 4 :(得分:3)

我看到你正在尝试使用静态变量,因为songpaths,alldirectorypaths,internalpaths ..可能是只应存在于应用程序中访问的一个实例中的值。 你需要的是使用单例模式。

  

单例模式是一种设计模式,它将类的实例化限制为一个对象。当需要一个对象来协调整个系统的操作时,这非常有用。 (维基百科)

根据Joshua Bloch的“Effective Java”一书,实现单例的最有效方法是使用Enums。

  public enum MusicPlayerContext{

    INSTANCE;

    public List<String> internalpaths = new ArrayList<String>();
    public List<String> alldirectorypaths= new ArrayList<String>();

  }

  public class MyActivity extends Activity{

      public void doSomething(){
         List<String> intPaths = MusicPlayerContext.INSTANCE.internalpaths; 
      }
  }

还有一件事..更喜欢使用接口进行变量声明(List)而不是实现(ArrayList&lt; String&gt;)

答案 5 :(得分:3)

static是线程不安全的,如果您不想使用get()/ set()函数,则可以使用public来修改基本数据类型。

像这样定义点:

public class Point{
    public double x;
    public double y;
}

然后像这样使用Point:

Point p = new Point();
p.x = ;
p.y = ;

但是,对于Object数据类型,最好使用get()/ set()函数,它们是安全的。

答案 6 :(得分:3)

这个问题已经回答here

我个人会使用Singleton Pattern,它非常容易实现,使您的代码更容易测试,将来更容易更改。

关键是,对于静态变量,您必须在客户端的任何地方编写arguments,并将客户端耦合到此特定类。

使用单身人士,你可以,f.i。,介绍一个界面,然后将来很容易用另一个替换单身人士。

Singleton实现也允许延迟初始化。

答案 7 :(得分:3)

在像C ++这样的本地语言中,使用getter(i = getCount())而不是直接访问字段(i = mCount)是常见做法。这是C ++的一个很好的习惯,并且经常用于其他面向对象的语言,如C#和Java,因为编译器通常可以内联访问,如果您需要限制或调试字段访问,您可以随时添加代码。 / p>

然而,这在Android上是一个坏主意。虚拟方法调用比实例字段查找要昂贵得多。遵循常见的面向对象编程实践并在公共接口中使用getter和setter是合理的,但在类中,您应该始终直接访问字段。

因此,作为Android开发人员指南,您应该避免使用getter / setter()。

参考:http://developer.android.com/training/articles/perf-tips.html

答案 8 :(得分:2)

对于上下文,让我们简单地谈谈static的作用。 static是一个关键字,它将变量的范围更改为全局,在所有实例中保持其值,并在应用程序的生命周期内永久分配内存。

这有一些后果:

  • 变量对于线程环境变得不安全
  • 变量(如果是公开的话)可以在任何地方访问
  • 变量永远不会通过垃圾回收清理

为了更好地执行您使用static完成的工作,我们可以使用interface

制作新的interface

public interface FragmentActivityInterface {
  String getSongPath(int index);
  //etc...
}

Fragment实施interface

public class Fragmentactivity extends FragmentActivity implements FragmentActivityInterface {

    static ArrayList<String> s3=new ArrayList<String>();
    static ArrayList<String> s5=new ArrayList<String>();
    static ArrayList<String> songpaths=new ArrayList<String>();
    static ArrayList<String> alldirectorypaths=new ArrayList<String>();
    static ArrayList<String> internalpaths=new ArrayList<String>();
    static ArrayList<String> tempsongnames=new ArrayList<String>();
    static ArrayList<Bitmap> thumbnails=new ArrayList<Bitmap>();
    static int internal=0;
    static ArrayList<String> folderpaths=new ArrayList<String>();
    //my addtional code after it

    @Override
    public String getSongPath(int index) {
        return songpaths.get(index);
    }

    //etc...
}

让您的其他课程需要FragmentActivityInterface

public class A {
  private FragmentActivityInterface fragInterface;

  public A (FragmentActivityInterface fragInterface) {
    this.fragInterface = fragInterface;
  }
}

最后,当您创建A课程的实例时,您只需传入您的活动。

A foo = new A(this);

现在,在A您想要访问FragmentActivity成员的任何地方,只需使用fragInterface.getSongPath(0)