精华内容
下载资源
问答
  • Java中声明常量为什么用static修饰

    千次阅读 2015-07-31 17:27:08
    做Android开发的时候,只要查看一些Android源码,不难发现,其中,声明常量都是如下格式: ...之前是这么考虑问题的:定义一个A,其中包含了静态变量修饰的常量CONSTANT_A与直接final修饰的常量CONSTANT_B pub

    在做Android开发的时候,只要查看一些Android源码,不难发现,其中,声明常量都是如下格式:

    <span style="font-size:14px;">private static final String TAG = "FragmentActivity";</span>

    声明为什么要添加static关键字呢?

    之前是这么考虑问题的:定义一个类A,其中包含了用静态变量修饰的常量CONSTANT_A与直接用final修饰的常量CONSTANT_B

    <span style="font-size:14px;">public class A {
        public static final String CONSTANT_A = "Hello";
        public final String CONSTANT_B = "Hello";
    }</span>

    在创建多个A的对象时,常量A在内存中只有一份拷贝,而B则有多个拷贝,后者显然使我们不希望看到的。


    今天在看Android官网的时候,恰巧看到这一问题:

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

    原文:

    Use Static Final For Constants


    Consider the following declaration at the top of a class:

    static int intVal = 42;
    static String strVal = "Hello, world!";

    The compiler generates a class initializer method, called <clinit>, that is executed when the class is first used. The method stores the value 42 into intVal, and extracts a reference from the classfile string constant table for strVal. When these values are referenced later on, they are accessed with field lookups.

    在类第一次被执行的时候,编译器会生成一个初始化方法,这个方法将42的值存入对应的变量intVal,同时通过常量表获得strVal的一个引用。在之后引用这些变量的时候,将进行查询(表)来访问到。

    We can improve matters with the "final" keyword:

    通过使用final来提升性能:

    static final int intVal = 42;
    static final String strVal = "Hello, world!";

    The class no longer requires a <clinit> method, because the constants go into static field initializers in the dex file. Code that refers to intVal will use the integer value 42 directly, and accesses to strVal will use a relatively inexpensive "string constant" instruction instead of a field lookup.

    这样,常量进入了dex文件的静态区初始化部分,不在需要一个初始化方法(来对变量赋值),代码中将直接使用42的常量值,strVal也通过开销低廉的“字符串常量”来代替文件查表。

    Note: This optimization applies only to primitive types and String constants, not arbitrary reference types. Still, it's good practice to declare constants static final whenever possible.

    最有的一个小提示:这种右划仅对基本数据类型和String常量有效果,不包括其他引用类型。


    看完Google的这段文章,虽然对里面部分名词还是稍有不解,但是了解到static final搭档的另外原因。

    展开全文
  • python中我们经常听到\看到一函数A,函数的定义声明(def)之前还有类似于@xxx的记号。对于这函数A我们称之为被修饰的函数,而对于@中的xxx我们称之为函数装饰器 ...

    1.函数装饰器的定义

    在python中我们经常听到\看到一类函数A,在这类函数的定义声明(def)之前还有类似于@xxx的记号。对于这类函数A,我们称之为被修饰的函数,而对于 @中的xxx 我们称之为函数装饰器(function decorator)
    譬如说,对于如下代码片段

    # example:
    def funcShell(func):
    	def decorator(**kws):
    	#**kws是指关键字参数 (keyword arguments),没什么卵用
    		print("decorator方法被使用!")
    		#lz直接把函数(function)叫成方法(method)了
    		#其实是一个事儿
    		return func(**kws)
    	return decorator
    	
    @funcShell
    def funcInput():
    	print("funcInput方法被使用!")
    	return None #此处的return没用,可忽略
    if __name__ == '__main__':
    #主程序调用方法的标准格式,起到用来调式代码的作用
    	funcInput()

    打印结果如下:

    decorator方法被使用!
    funcInput方法被使用!

    在上述代码中,funcShell就起到了函数装饰器的作用,被装饰的方法就是funcInput()。实际上的执行顺序为:funcShell(funcInput);所以我们看到结果才是先执行了funcShell中的打印语句,然后才执行了funcInput中的打印语句。

    2.函数装饰器的作用

    函数装饰器(decorator)最根本的最用在于“对现有程序的再利用”,说白了就是为了偷懒。虽然说人类的本质是复读机,但是偷懒还是人类的天性。为了最大程度上实现对现有程序的利用,如果只需要改变程序的输入或输出的部分步骤,而不需要对程序的主体进行修改,那就可以用到函数装饰器来偷懒
    分析上述代码之前,我们需要知道:传入函数(方法)中的参数不仅仅可以是一般类型或者引用类型的数据,甚至还可以是函数(方法)本身。例如,

    def func_one(**kws):
    	print("func_one has been used!")
    	return None
    def func_test(func):
    	func()
    	return None
    if __name__ == '__main__':
    	func_test(func_one)	

    在上述程序中,func_one函数就以参数(parameter)的形式传入到了func_test函数中。


    同理,对于函数装饰器我们一样可以看作是把一个现成的函数传入到装饰器中去,并在该函数执行的前后空间内进行额外的操作,赋予原来函数还不具有的某些功能。

    3.如何在类中定义函数装饰器?

    lz曾经想在类中也定义装饰器,但是弄了很久才解决问题。主要的问题处在类中定义的方法相关的参数的传递上。以如下代码片段为例。

    from functools import wraps
    class Test(object):
    	def __init__(self):
    		print("初始化完成")
    		return None
    	def funcShell(func):
    		@wraps(func)
    		def decorator(self, **kws):
    		#**kws是指关键字参数 (keyword arguments),没什么卵用
    			print("decorator方法被使用!")
    			#lz直接把函数(function)叫成方法(method)了
    			#其实是一个事儿
    			return func(self, **kws)
    		return decorator
    		
    	@funcShell
    	def funcInput(self):
    		print("funcInput方法被使用!")
    		return None #此处的return没用,可忽略
    if __name__ == '__main__':
    	object_example = Test()
    	Test.funcInput()

    打印结果如下:

    decorator方法被使用!
    funcInput方法被使用!

    结果与非类方法一般方法定义所给出的结果是一致的。唯一需要注意的问题在于:对于类定义中的方法我们不需要在外层壳子Shell的参数中绑定self只需要在wraps所定义的内层方法Kernal中加入self参数,同时在wraps所作用的decorator的返回值中给出形如输入函数(self, **kws)的形式,即可实现函数装饰器的功能。


    这主要是因为,返回的装饰后的函数需要凭借self来提供一个类似于调用的接口

    4.结论

    函数装饰器作为修改原有函数(方法)的偷懒神器,在提高人类社会生产效率的历史上留下了浓墨重彩的一笔。 :)

    展开全文
  • 1.函数装饰器的定义python中我们经常听到\看到一函数A,函数的定义声明(def)之前还有类似于@xxx的记号。对于这函数A,我们称之为被修饰的函数,而对于 @中的xxx 我们称之为函数装饰器(function ...

    1.函数装饰器的定义

    在python中我们经常听到\看到一类函数A,在这类函数的定义声明(def)之前还有类似于@xxx的记号。对于这类函数A,我们称之为被修饰的函数,而对于 @中的xxx 我们称之为函数装饰器(function decorator)。

    譬如说,对于如下代码片段。

    # example:

    def funcShell(func):

    def decorator(**kws):

    #**kws是指关键字参数 (keyword arguments),没什么卵用

    print("decorator方法被使用!")

    #lz直接把函数(function)叫成方法(method)了

    #其实是一个事儿

    return func(**kws)

    return decorator

    @funcShell

    def funcInput():

    print("funcInput方法被使用!")

    return None #此处的return没用,可忽略

    if __name__ == '__main__':

    #主程序调用方法的标准格式,起到用来调式代码的作用

    funcInput()

    打印结果如下:

    decorator方法被使用!

    funcInput方法被使用!

    在上述代码中,funcShell就起到了函数装饰器的作用,被装饰的方法就是funcInput()。实际上的执行顺序为:funcShell(funcInput);所以我们看到结果才是先执行了funcShell中的打印语句,然后才执行了funcInput中的打印语句。

    2.函数装饰器的作用

    函数装饰器(decorator)最根本的最用在于“对现有程序的再利用”,说白了就是为了偷懒。虽然说人类的本质是复读机,但是偷懒还是人类的天性。为了最大程度上实现对现有程序的利用,如果只需要改变程序的输入或输出的部分步骤,而不需要对程序的主体进行修改,那就可以用到函数装饰器来偷懒。

    分析上述代码之前,我们需要知道:传入函数(方法)中的参数不仅仅可以是一般类型或者引用类型的数据,甚至还可以是函数(方法)本身。例如,

    def func_one(**kws):

    print("func_one has been used!")

    return None

    def func_test(func):

    func()

    return None

    if __name__ == '__main__':

    func_test(func_one)

    在上述程序中,func_one函数就以参数(parameter)的形式传入到了func_test函数中。

    同理,对于函数装饰器我们一样可以看作是把一个现成的函数传入到装饰器中去,并在该函数执行的前后空间内进行额外的操作,赋予原来函数还不具有的某些功能。

    3.如何在类中定义函数装饰器?

    lz曾经想在类中也定义装饰器,但是弄了很久才解决问题。主要的问题处在类中定义的方法相关的参数的传递上。以如下代码片段为例。

    from functools import wraps

    class Test(object):

    def __init__(self):

    print("初始化完成")

    return None

    def funcShell(func):

    @wraps(func)

    def decorator(self, **kws):

    #**kws是指关键字参数 (keyword arguments),没什么卵用

    print("decorator方法被使用!")

    #lz直接把函数(function)叫成方法(method)了

    #其实是一个事儿

    return func(self, **kws)

    return decorator

    @funcShell

    def funcInput(self):

    print("funcInput方法被使用!")

    return None #此处的return没用,可忽略

    if __name__ == '__main__':

    object_example = Test()

    Test.funcInput()

    打印结果如下:

    decorator方法被使用!

    funcInput方法被使用!

    结果与非类方法的一般方法定义所给出的结果是一致的。唯一需要注意的问题在于:对于类定义中的方法我们不需要在外层壳子Shell的参数中绑定self,只需要在wraps所定义的内层方法Kernal中加入self参数,同时在wraps所作用的decorator的返回值中给出形如输入函数(self, **kws)的形式,即可实现函数装饰器的功能。

    这主要是因为,返回的装饰后的函数需要凭借self来提供一个类似于调用的接口。

    4.结论

    函数装饰器作为修改原有函数(方法)的偷懒神器,在提高人类社会生产效率的历史上留下了浓墨重彩的一笔。 :)

    展开全文
  • 抽象类定义在了解抽象类之前,先来知道什么是...如果一个类含有抽象方法,则称这个类为抽象类,抽象类必须在类abstract关键字修饰。因为抽象类中含有无具体实现的方法,所以不能抽象类创建对象。[public] abst

    这里写图片描述

    抽象类定义

    在了解抽象类之前,先来知道什么是抽象方法。抽象方法是一种特殊的方法:它只有声明,而没有具体的实现。抽象方法的声明格式为:

    abstract void function();

    抽象方法必须用abstract关键字进行修饰。

    如果一个类含有抽象方法,则称这个类为抽象类,抽象类必须在类前用abstract关键字修饰。因为抽象类中含有无具体实现的方法,所以不能用抽象类创建对象。

    [public] abstract class ClassName {
        //抽象方法
        abstract void function();
    }

    抽象类就是为了继承而存在的,如果你定义了一个抽象类,却不去继承它,那么等于白创建了这个抽象类,因为你不能用它来做任何事情。对于一个父类,如果它的某个方法在父类中实现出来没有任何意义,必须根据子类的实际需求来进行不同的实现,那么就可以将这个方法声明为abstract方法,此时这个类也就成为abstract类了。

    注意,抽象类和普通类的主要有三点区别:

    • 抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。
    • 抽象类不能用来创建对象;
    • 如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。

    我们定义一个典型的抽象类门–Door:

    //抽象类门
    public abstract class Door{
        //变量门的id
        private int id;
        //抽象方法开门:open
        abstract void open();
        //抽象方法关门:close
        abstract void close();
        //设置id主方法
        public void setID(int id){
            this.id = id;
        }
    }

    接口定义

    接口,英文称作interface,在软件工程中,接口泛指供别人调用的方法或者函数。从这里,我们可以体会到Java语言设计者的初衷,接口是对行为的抽象,指定类必须执行哪些方法,接口只定义方法,不具体实现方法的内容。

    在Java中,定一个接口的形式如下:

    [public] interface InterfaceName {
        [public abstract] void function(); 
    }

    接口中可以含有变量和方法, 但是接口中的变量会被隐式地指定为public static final变量(并且只能是public static final变量),而方法会被隐式地指定为public abstract方法(且只能是public abstract方法),并且接口中所有的方法不能有具体的实现,也就是说,接口中的方法必须都是抽象方法。从这里可以看出接口和抽象类的区别,接口是一种极度抽象的类型,它比抽象类更加“抽象”,并且一般情况下不在接口中定义变量。

    我们定义一个典型的接口类报警行为–Alarm:

    public interface IAlarm{
        //报警方法alarm
        void alarm(); 
    }

    抽象类和接口的不同

    语法层面上的区别

    • 抽象类可以拥有任意范围和类型的成员数据,同时也可以拥有非抽象方法,而接口仅能够有public static final 的成员数据(但是我们一般是不会在接口中使用成员数据),同时它所有的方法都必须是public abstract的。
    • 一个类只能继承一个抽象类,而一个类却可以实现多个接口。

    设计层面上的区别

    • 抽象层次不同

    抽象类是对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类的行为进行抽象。

    • 跨域不同

    抽象类所跨域的是具有相似特点的类,而接口却可以跨域不同的类。我们知道抽象类是从子类中发现公共部分,然后泛化成抽象类,子类继承该父类即可,但是接口不同,实现它的子类可以不存在任何关系,共同之处,只需要有相同的行为就可以。

    例如猫、狗可以抽象成一个动物类抽象类,具备cry的方法。鸟、飞机可以实现飞Fly接口,具备飞的行为,这里我们总不能将鸟、飞机共用一个父类吧!所以说抽象类所体现的是一种继承关系,要想使得继承关系合理,父类和派生类之间必须存在”is-a” 关系,即父类和派生类在概念本质上应该是相同的。对于接口则不然,并不要求接口的实现者和接口定义在概念本质上是一致的, 仅仅是实现了接口定义的契约而已。

    • 设计层次不同

    对于抽象类而言,它是自下而上来设计的,我们要先知道子类才能抽象出父类,而接口则不同,接口是自顶向下设计出来的,它根本就不需要知道子类的存在,只需要定义一个规则即可,至于什么子类、什么时候怎么实现它一概不知。

    比如我们只有一个猫类在这里,如果你这是就抽象成一个动物类,是不是设计有点儿过度?我们起码要有两个动物类,猫、狗在这里,我们在抽象他们的共同点形成动物抽象类吧,所以说抽象类往往都是通过重构而来的!但是接口就不同,比如说飞,我们根本就不知道会有什么东西来实现这个飞接口,怎么实现也不得而知,我们要做的就是事前定义好飞的行为接口。

    所以说抽象类是自底向上抽象而来的,接口是自顶向下设计出来的。

    一个经典的例子

    下面看一个网上流传最广泛的例子:门和警报的例子,来更好的理解抽象类和接口。

    门都有open( )和close( )两个动作,此时我们可以定义通过抽象类和接口来定义这个抽象概念:

    abstract class Door {
        public abstract void open();
        public abstract void close();
    }
    interface IDoor {
        public abstract void open();
        public abstract void close();
    }

    但是现在如果我们需要门具有报警alarm( )的功能,那么该如何实现?下面提供两种思路:
    1)将这三个功能都放在抽象类里面,但是这样一来所有继承于这个抽象类的子类都具备了报警功能,但是有的门并不一定具备报警功能;
    2)将这三个功能都放在接口里面,需要用到报警功能的类就需要实现这个接口中的open( )和close( ),也许这个类根本就不具备open( )和close( )这两个功能,比如火灾报警器。

    从这里可以看出, Door的open() 、close()和alarm()根本就属于两个不同范畴内的行为,open()和close()属于门本身固有的行为特性,而alarm()属于延伸的附加行为。
    因此最好的解决办法是单独将报警设计为一个接口,包含alarm()行为,Door设计为单独的一个抽象类,包含open和close两种行为。再设计一个报警门继承Door类和实现Alarm接口。

    interface IAlram {
        void alarm();
    }
    
    abstract class Door {
        void open();
        void close();
    }
    
    class AlarmDoor extends Door implements IAlarm {
        void oepn() {
          //....
        }
        void close() {
          //....
        }
        void alarm() {
          //....
        }
    }

    总结

    1.抽象类在java语言中所表示的是一种继承关系(is-a),一个子类只能存在一个父类(单继承),接口是定义模块间的通信契约关系(like-a),一个子类可以实现多个接口(多实现接口)。
    2.在抽象类中可以拥有自己的成员变量和非抽象类方法,但是接口中只能存在public static final的成员数据(不过一般都不在接口中定义成员数据),而且它的所有方法都是public abstract的。
    3.抽象类和接口所反映的设计理念是不同的,抽象类所代表的是“is-a”的关系,而接口所代表的是“like-a”的关系。

    参考资料

    1.java提高篇(四)—–抽象类与接口
    http://blog.csdn.net/chenssy/article/details/12858267
    2.深入理解Java的接口和抽象类
    http://blog.csdn.net/e01014165/article/details/51926249
    3.深入浅出:重温JAVA中接口与抽象的区别
    http://www.cnblogs.com/luihengk/p/3960273.html
    4.抽象类与接口的区别
    http://blog.csdn.net/ttgjz/article/details/2960451

    展开全文
  • 讲解权限修饰之前,我们要先了解一下什么是包 package: 包   作用:用于管理源文件,区分全名  命名规则:域名后缀.域名.项目名.模块名  声明位置:源文件的首行首句。  全名:从包开始写起的名称...
  • 抽象——java

    2018-05-04 18:21:05
    了解抽象类之前,先了解一下抽象方法。抽象方法是一种特殊的方法:只有声明,没有具体的实现(没有函数体)。抽象方法声明格式为:abstract void fun();//没有大括弧“{ }”抽象注意点:1、抽象方法或抽象...
  • 在了解Java中接口与抽象类的区别之前首先我们需要分别了解抽象类和接口到底是什么。 抽象类  在了解抽象类之前,先来了解一下...如果一个类含有抽象方法,则称这个类为抽象类,抽象类必须在类abstract关键字...
  • 引入什么是Java常量?参考:常量常量的声明...通过interface来创建,接口默认创建的变量会被static、final修饰在普通中,通过static 、final修饰的变量通过Enum来创建接口常量JDK1.5之前,没有枚举,有的的接...
  • 面向对象

    2019-08-05 12:57:29
    我们要先理解什么同一个JAVA文件中我们可以创造多个不同的类名,但只能有一个可以public 修饰public修饰的类名必须与java文件的名字一致。(这里声明一下,访问权限修饰符共有,1.public(共有的)2...
  • 一小时内学会 C#(txt版本)

    热门讨论 2009-08-19 18:09:37
    C# 中所有内容都打包在类中,而所有的类又打包在命名空间中(正如文件存与文件夹中)。和 C++ 一样,有一个主函数作为你程序的入口点。C++ 的主函数名为 main,而 C# 中是大写 M 打头的 Main。 类块或结构定义之后...
  • java的变量

    2021-01-01 15:58:54
    说变量之前,我们先来回顾一下什么是常量。常量就是整个程序生命周期中,值不会发生改变。比如final修饰的变量,值不可再发生更改。 一、变量的定义 变量:程序的生命周期中,值可以发生变化的量。 二、全局...
  • 声明方法的存在而不去实现它的类被叫做抽象类(abstract class),它用于要创建一个体现某些基本行为的类,并为该类声明方法,但不能该类中实现该类的情况。不能创建abstract 类的实例。然而可以创建一个变量,其...
  • Java注解

    2015-09-02 22:28:31
    Annotation是一种应用于、方法、参数、变量、构造器及包声明中的特殊修饰符。它是一种由JSR-175标准选择用来描述元数据的一种工具注解有什么用?使用Annotation之前(甚至使用之后),XML被广泛的应用于描述元数据...
  • 而且它只会出现在类中的构造函数声明之前。 其次,explicit关键字是用来抑制由构造函数定义的隐式转换的。那么我们首先需要知道什么是由构造函数定义的隐式转换? 下面的代码演示了这种转换:   [cpp]
  • TerrariaClone 讨论于: , , , 。... 为了避免声明局部变量和循环索引,所有内容的所有变量都在类级别全局声明。 这是TerrariaClone.java几百行声明之一: int x, y, i, j, k, t, wx, wy, lx, ly, tx, ty,
  • JAVA面试题最全集

    2010-03-13 13:09:10
    多线程,用什么关键字修饰同步方法?stop()和suspend()方法为何不推荐使用? 59.使用socket建立客户端与服务器的通信的过程 60.JAVA语言国际化应用,Locale,Unicode 61.描述反射机制的作用 62.如何读写一个...
  • 11.5.1 C# 4.0中使用out类型参数修饰符允许协变性 331 11.5.2 C# 4.0中使用in类型参数修饰符允许逆变性 332 11.5.3 数组对不安全协变性的支持 335 11.6 泛型的内部机制 335 11.6.1 基于值...
  • c#学习笔记.txt

    2008-12-15 14:01:21
    在类中,必须初始化实例对象. 使用 new 运算符创建结构对象时,将创建该结构对象,并且调用适当的构造函数。与类不同的是,结构的实例化可以不使用 new 运算符。如果不使用 new,那么在初始化所有字段之前,字段将...
  • 自己写的dll的简介

    2009-12-12 10:17:40
    对于DLL的用户来讲,类声明就需要另外一个关键字__declspec(dllimport)(此关键字对于类和函数而言并非必须,但对于变量而言则是必须的)。所以通常我们会定义一个宏来包装之,比如 #ifdef MYDLL_EXPORTS # ...
  • instance属性在创建实例的时候初始化,static属性在类加载,也就是第一次用到这个类的时候初始化,对于后来的实例的创建,不再次进行初始化。这个问题会在以后的系列中进行详细讨论。对于第二种变量,必须明确地进行...

空空如也

空空如也

1 2 3
收藏数 56
精华内容 22
关键字:

在类声明之前用什么修饰