精华内容
下载资源
问答
  • Java中类与对象的定义与使用

    千次阅读 多人点赞 2018-10-31 20:38:54
     把客观事物封装成抽象的,每个都有自己的属性与方法,并且可以让自己的数据和方法只让可信的或对象操作,对不可信的进行信息隐藏。内部操作对外部而言不可见(保护) 0.2 继承  它可以是现有的...

    0. 面向对象的三大特征

    0.1 封装性

     把客观事物封装成抽象的类,每个类都有自己的属性与方法,并且类可以让自己的数据和方法只让可信的类或对象操作,对不可信的进行信息隐藏。内部操作对外部而言不可见(保护性)

    0.2 继承性

     它可以是现有类的所有功能,并且再无需重新编写原有类的代码的情况下对这些功能进行扩展。

    0.3 多态性(重点)

     指一个类实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。
    面对对象的最大特征就是:可以进行生活的抽象

    1. 类与对象的概念

    类是共性的概念,而对象是一个具体、可以使用的事物。类是声场对象的蓝图,现有类才可以产生对象。对象的所有属性与行为,一定在类中进行了完整的定义。
    在这里插入图片描述

    1.1 类中的组成

    1. 方法(操作的行为)
    2. 属性(变量,描述每个对象的具体特点)

    2. 类与对象的定义与使用

    2.1 类的定义

    class 类名称{
    	属性1;
    	属性2;
    	……
    	方法1;
    	方法2;
    	……
    }
    

    举例:定义一个Person类

    class Person{
        // 属性
        public String name;
        public int age;
        // 构造方法
        public Person(String name, int age){
            this.name = name;
            this.age = age;
        }
        // 普通方法
        public String getPersonInfo(){
            return "姓名:" + this.name + "年龄:" + this.age;
        }
    }
    

    类中的属性与方法(不带static关键字的)只能通过对象调用。

    2.2 对象的产生

    类名称 对象名称 = new 类名称();
    

    以Person类为例,可以产生一个Person类的实例(对象):

           Person per1 = new Person();
           Person per2 = new Person("zhangsan", 12); 
    

    2.3 通过对象调用实例变量与实例方法

    只要出现了关键字new,就开辟了内存。

            Person per = new Person("zhangsan", 18);
            System.out.println(per.name);
            System.out.println(per.getPersonInfo());
    

    运行结果如下图所示:
    在这里插入图片描述

    3. 对象的内存分析

     先简单的将Java中的内存区域分为 * 栈内存* 和 堆内存 (实际Java的内存区域的划分远比这个复杂)

    1. 栈内存(虚拟机局部变量表):存放的是局部变量(包含编译期可知的各种基本数据类型、对象引用—>即堆内存地址—>对象的名称),Java栈是与线程对应起来的,每当创建一个线程,JVM就会为这个线程创建一个对应的Java栈。
    2. 堆内存:保存的是真正的数据,即对象的属性信息。

    new表示在对上新分配的空间。
    举例:通过以下代码和内存分析给大家讲解一下内存:

    class Person{
        // 属性
        String name;
        int age;
    }
    public class Test{
        public static void main(String[] args){
            Person per = new Person();
            System.out.println(per.name + "  " + per.age);
            per.name = "zhangsan";
            per.age = 18;
            System.out.println(per.name + "  " + per.age);
        }
    }
    

    以上代码运行后得:
    在这里插入图片描述
    以下按步骤进行分析,对应代码及内存图:

    Person per = new Person();
    

    在这里插入图片描述

            per.name = "zhangsan";
            per.age = 18;
    

    通过per引用设置堆属性值,内存图如下所示:
    在这里插入图片描述
    对象(引用数据类型)必须在实例化后调用,否则会产生NullPointerException(运行时错误),编译时不会出错"NullPointerException"在开发生涯中会一直存在,只有引用类型(数组、类、接口)才会产生此类异常。以后此类异常,就根据出错位置查看引用数据类型变量是否初始化。

    4. 引用传递分析

    引用传递的本质:一块堆内存可以被多个栈内存所指向

            Person per1 = new Person();
            Person per2 = new Person();
            per2 = per1;
    

    前两句代码的内存图如下:
    在这里插入图片描述
    当 per2 = per1; 执行后,内存会怎么样变化?
    在这里插入图片描述
    垃圾空间: 没有任何栈内存指向的堆内存空间。
    所有垃圾空间会不定期GC(垃圾收集),GC会影响性能,所以开发之中一定要控制好对象的产生数量(无用的对象尽量少产生)

    展开全文
  • java安全编码指南之:可见性和原子性

    万次阅读 热门讨论 2020-09-25 10:57:36
    java类中定义很多变量,有变量也有实例变量,这些变量访问的过程,会遇到一些可见性和原子性的问题。这里我们来详细了解一下怎么避免这些问题。

    简介

    java类中会定义很多变量,有类变量也有实例变量,这些变量在访问的过程中,会遇到一些可见性和原子性的问题。这里我们来详细了解一下怎么避免这些问题。

    不可变对象的可见性

    不可变对象就是初始化之后不能够被修改的对象,那么是不是类中引入了不可变对象,所有对不可变对象的修改都立马对所有线程可见呢?

    实际上,不可变对象只能保证在多线程环境中,对象使用的安全性,并不能够保证对象的可见性。

    先来讨论一下可变性,我们考虑下面的一个例子:

    public final class ImmutableObject {
        private final int age;
        public ImmutableObject(int age){
            this.age=age;
        }
    }
    

    我们定义了一个ImmutableObject对象,class是final的,并且里面的唯一字段也是final的。所以这个ImmutableObject初始化之后就不能够改变。

    然后我们定义一个类来get和set这个ImmutableObject:

    public class ObjectWithNothing {
        private ImmutableObject refObject;
        public ImmutableObject getImmutableObject(){
            return refObject;
        }
        public void setImmutableObject(int age){
            this.refObject=new ImmutableObject(age);
        }
    }
    

    上面的例子中,我们定义了一个对不可变对象的引用refObject,然后定义了get和set方法。

    注意,虽然ImmutableObject这个类本身是不可变的,但是我们对该对象的引用refObject是可变的。这就意味着我们可以调用多次setImmutableObject方法。

    再来讨论一下可见性。

    上面的例子中,在多线程环境中,是不是每次setImmutableObject都会导致getImmutableObject返回一个新的值呢?

    答案是否定的。

    当把源码编译之后,在编译器中生成的指令的顺序跟源码的顺序并不是完全一致的。处理器可能采用乱序或者并行的方式来执行指令(在JVM中只要程序的最终执行结果和在严格串行环境中执行结果一致,这种重排序是允许的)。并且处理器还有本地缓存,当将结果存储在本地缓存中,其他线程是无法看到结果的。除此之外缓存提交到主内存的顺序也肯能会变化。

    怎么解决呢?

    最简单的解决可见性的办法就是加上volatile关键字,volatile关键字可以使用java内存模型的happens-before规则,从而保证volatile的变量修改对所有线程可见。

    public class ObjectWithVolatile {
        private volatile ImmutableObject refObject;
        public ImmutableObject getImmutableObject(){
            return refObject;
        }
        public void setImmutableObject(int age){
            this.refObject=new ImmutableObject(age);
        }
    }
    

    另外,使用锁机制,也可以达到同样的效果:

    public class ObjectWithSync {
        private  ImmutableObject refObject;
        public synchronized ImmutableObject getImmutableObject(){
            return refObject;
        }
        public synchronized void setImmutableObject(int age){
            this.refObject=new ImmutableObject(age);
        }
    }
    

    最后,我们还可以使用原子类来达到同样的效果:

    public class ObjectWithAtomic {
        private final AtomicReference<ImmutableObject> refObject= new AtomicReference<>();
        public ImmutableObject getImmutableObject(){
            return refObject.get();
        }
        public void setImmutableObject(int age){
            refObject.set(new ImmutableObject(age));
        }
    }
    

    保证共享变量的复合操作的原子性

    如果是共享对象,那么我们就需要考虑在多线程环境中的原子性。如果是对共享变量的复合操作,比如:++, – *=, /=, %=, +=, -=, <<=, >>=, >>>=, ^= 等,看起来是一个语句,但实际上是多个语句的集合。

    我们需要考虑多线程下面的安全性。

    考虑下面的例子:

    public class CompoundOper1 {
        private int i=0;
        public int increase(){
            i++;
            return i;
        }
    }
    

    例子中我们对int i进行累加操作。但是++实际上是由三个操作组成的:

    1. 从内存中读取i的值,并写入CPU寄存器中。
    2. CPU寄存器中将i值+1
    3. 将值写回内存中的i中。

    如果在单线程环境中,是没有问题的,但是在多线程环境中,因为不是原子操作,就可能会发生问题。

    解决办法有很多种,第一种就是使用synchronized关键字

        public synchronized int increaseSync(){
            i++;
            return i;
        }
    

    第二种就是使用lock:

        private final ReentrantLock reentrantLock=new ReentrantLock();
    
        public int increaseWithLock(){
            try{
                reentrantLock.lock();
                i++;
                return i;
            }finally {
                reentrantLock.unlock();
            }
        }
    

    第三种就是使用Atomic原子类:

        private AtomicInteger atomicInteger=new AtomicInteger(0);
    
        public int increaseWithAtomic(){
            return atomicInteger.incrementAndGet();
        }
    

    保证多个Atomic原子类操作的原子性

    如果一个方法使用了多个原子类的操作,虽然单个原子操作是原子性的,但是组合起来就不一定了。

    我们看一个例子:

    public class CompoundAtomic {
        private AtomicInteger atomicInteger1=new AtomicInteger(0);
        private AtomicInteger atomicInteger2=new AtomicInteger(0);
    
        public void update(){
            atomicInteger1.set(20);
            atomicInteger2.set(10);
        }
    
        public int get() {
            return atomicInteger1.get()+atomicInteger2.get();
        }
    }
    

    上面的例子中,我们定义了两个AtomicInteger,并且分别在update和get操作中对两个AtomicInteger进行操作。

    虽然AtomicInteger是原子性的,但是两个不同的AtomicInteger合并起来就不是了。在多线程操作的过程中可能会遇到问题。

    同样的,我们可以使用同步机制或者锁来保证数据的一致性。

    保证方法调用链的原子性

    如果我们要创建一个对象的实例,而这个对象的实例是通过链式调用来创建的。那么我们需要保证链式调用的原子性。

    考虑下面的一个例子:

    public class ChainedMethod {
        private int age=0;
        private String name="";
        private String adress="";
    
        public ChainedMethod setAdress(String adress) {
            this.adress = adress;
            return this;
        }
    
        public ChainedMethod setAge(int age) {
            this.age = age;
            return this;
        }
    
        public ChainedMethod setName(String name) {
            this.name = name;
            return this;
        }
    }
    

    很简单的一个对象,我们定义了三个属性,每次set都会返回对this的引用。

    我们看下在多线程环境下面怎么调用:

            ChainedMethod chainedMethod= new ChainedMethod();
            Thread t1 = new Thread(() -> chainedMethod.setAge(1).setAdress("www.flydean.com1").setName("name1"));
            t1.start();
    
            Thread t2 = new Thread(() -> chainedMethod.setAge(2).setAdress("www.flydean.com2").setName("name2"));
            t2.start();
    

    因为在多线程环境下,上面的set方法可能会出现混乱的情况。

    怎么解决呢?我们可以先创建一个本地的副本,这个副本因为是本地访问的,所以是线程安全的,最后将副本拷贝给新创建的实例对象。

    主要的代码是下面样子的:

    public class ChainedMethodWithBuilder {
        private int age=0;
        private String name="";
        private String adress="";
    
        public ChainedMethodWithBuilder(Builder builder){
            this.adress=builder.adress;
            this.age=builder.age;
            this.name=builder.name;
        }
    
        public static class Builder{
            private int age=0;
            private String name="";
            private String adress="";
    
            public static Builder newInstance(){
                return new Builder();
            }
            private Builder() {}
    
            public Builder setName(String name) {
                this.name = name;
                return this;
            }
    
            public Builder setAge(int age) {
                this.age = age;
                return this;
            }
    
            public Builder setAdress(String adress) {
                this.adress = adress;
                return this;
            }
    
            public ChainedMethodWithBuilder build(){
                return new ChainedMethodWithBuilder(this);
            }
        }
    

    我们看下怎么调用:

          final ChainedMethodWithBuilder[] builder = new ChainedMethodWithBuilder[1];
            Thread t1 = new Thread(() -> {
                builder[0] =ChainedMethodWithBuilder.Builder.newInstance()
                    .setAge(1).setAdress("www.flydean.com1").setName("name1")
                    .build();});
            t1.start();
    
            Thread t2 = new Thread(() ->{
                builder[0] =ChainedMethodWithBuilder.Builder.newInstance()
                    .setAge(1).setAdress("www.flydean.com1").setName("name1")
                    .build();});
            t2.start();
    

    因为lambda表达式中使用的变量必须是final或者final等效的,所以我们需要构建一个final的数组。

    读写64bits的值

    在java中,64bits的long和double是被当成两个32bits来对待的。

    所以一个64bits的操作被分成了两个32bits的操作。从而导致了原子性问题。

    考虑下面的代码:

    public class LongUsage {
        private long i =0;
    
        public void setLong(long i){
            this.i=i;
        }
        public void printLong(){
            System.out.println("i="+i);
        }
    }
    

    因为long的读写是分成两部分进行的,如果在多线程的环境中多次调用setLong和printLong的方法,就有可能会出现问题。

    解决办法本简单,将long或者double变量定义为volatile即可。

    private volatile long i = 0;
    

    本文的代码:

    learn-java-base-9-to-20/tree/master/security

    本文已收录于 http://www.flydean.com/java-security-code-line-visibility-atomicity/

    最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

    欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

    展开全文
  • [译]JavaScript属性:定义和赋值的区别 原文:http://www.2ality.com/2012/08/property-definition-assignment.html 你知道吗?定义一个属性和为一个属性赋值是有区别的.本文解释了两者之间的区别以及各自的...
    [译]JavaScript中的属性:定义和赋值的区别

    原文:http://www.2ality.com/2012/08/property-definition-assignment.html

    你知道吗?定义一个属性和为一个属性赋值是有区别的.本文解释了两者之间的区别以及各自的作用影响.该话题来自于Allen Wirfs-Brock在es-discuss邮件列表中的一封邮件.

    1. 定义VS赋值

    定义(Definition).定义属性需要使用相应的函数,比如:

    Object.defineProperty(obj, "prop", propDesc)

    如果obj没有prop这个自身属性,则该函数的作用是给obj添加一个自身属性prop并赋值,参数propDesc指定了该属性拥有的特性(可写性,可枚举性等).如果obj已经有了prop这个自身属性,则该函数的作用是修改这个已有属性的特性,当然也包括它的属性值.

    赋值(assignment).为一个属性赋值需要使用下面的表达式:

    obj.prop = value

    如果obj已经有了prop这个自身属性,则该表达式的作用就是修改这个prop属性的值,反之,如果obj没有prop这个自身属性,则该表达式的操作结果就不一定了:首先会查找对象obj的原型链[1],如果原型链中的所有对象都没有名为prop的属性,则结果是在obj身上新建一个自身属性prop,新创建的属性拥有默认的属性特性,且把指定的value赋值给该属性.但如果obj的某个上层原型中上有一个名为prop的属性,那接下来的操作就复杂了,具体请看下面的3.2小节.

    2. 属性特性和内部属性

    2.1. 多种类型的属性

    JavaScript中有三种类型的属性:

    • 命名数据属性(named data properties): 拥有一个确定的值的属性.这也是最常用的属性.
    • 命名访问器属性(named accessor properties): 通过getter和setter进行读取和赋值的属性.
    • 内部属性(internal properties): 由JavaScript引擎内部使用的属性,不能通过JavaScript代码直接访问到,不过可以通过一些方法间接的读取和设置.比如:每个对象都有一个内部属性[[Prototype]],你不能直接访问这个属性,但可以通过Object.getPrototypeOf()方法间接的读取到它的值.虽然内部属性通常用一个双中括号包围的名称来表示,但实际上这并不是它们的名字,它们是一种抽象操作,是不可见的,根本没有上面两种属性有的那种字符串类型的属性名.

    2.2. 属性特性

    每个属性(property)都拥有4个特性(attribute).两种类型的属性一种有6种属性特性:

    • 命名数据属性特有的特性:
      • [[Value]]: 属性的值.
      • [[Writable]]: 控制属性的值是否可以改变.
    • 命名访问器属性特有的特性:
      • [[Get]]: 存储着getter方法.
      • [[Set]]: 存储着setter方法.
    • 两种属性都有的特性:
      • [[Enumerable]]: 如果一个属性是不可枚举的,则在一些操作下,这个属性是不可见的,比如for...in和Object.keys()[2].
      • [[Configurable]]: 如果一个属性是不可配置的,则该属性的所有特性(除了[[Value]])都不可改变.

    2.3. 属性描述符

    属性描述符(property descriptor)可以将一个属性的所有特性编码成一个对象并返回.例如:

    {
        value: 123,
        writable: false}

    属性描述符使用在下面的这些函数中:Object.definePropertyObject.getOwnPropertyDescriptorObject.create.如果省略了属性描述符对象中的某个属性,则该属性会取一个默认值:

    属性名 默认值
    value undefined
    get undefined
    set undefined
    writable false
    enumerable false
    configurable false

    2.4. 内部属性

    下面列举几个所有对象都有的内部属性:

    • [[Prototype]]: 对象的原型.
    • [[Extensible]]: 对象是否可以扩展,也就是是否可以添加新的属性.
    • [[DefineOwnProperty]]: 定义一个属性的内部方法.下一节会详细解释.
    • [[Put]]: 为一个属性赋值的内部方法.下一节会详细解释.

    3. 属性定义和属性赋值

    3.1. 属性定义

    定义属性是通过内部方法来进行操作的:

    [[  DefineOwnProperty]] (P, Desc, Throw)

    P是要定义的属性名称.参数Throw决定了在定义操作被拒绝的时候是否要抛出异常:如果Throw为true,则抛出异常.否则,操作只会静默失败.当调用[[DefineOwnProperty]]时,具体会执行下面的操作步骤.

    • 如果this没有名为P的自身属性的话:如果this是可扩展的话,则创建P这个自身属性,否则拒绝.
    • 如果this已经有了名为P的自身属性:则按照下面的步骤重新配置这个属性.
    • 如果这个已有的属性是不可配置的,则进行下面的操作会被拒绝:
      • 将一个数据属性转换成访问器属性,反之亦然
      • 改变[[Configurable]]或[[Enumerable]]
      • 该变[[Writable]]
      • 在[[Writable]]为false时改变[[Value]]
      • 改变[[Get]]或[[Set]]
    • 否则,这个已有的属性可以被重新配置.

    如果Desc就是P属性当前的属性描述符,则该定义操作永远不会被拒绝.

    定义属性的函数有两个:Object.defineProperty和Object.defineProperties.例如:

    Object.defineProperty(obj, propName, desc)

    在引擎内部,会转换成这样的方法调用:

    obj.[[DefineOwnProperty]](propName, desc, true)

    3.2. 属性赋值

    为属性赋值是通过内部方法进行操作的:

    [[  Put]] (P, Value, Throw)

    参数P以及Throw和[[DefineOwnProperty]]方法中的参数表现的一样.在调用[[Put]]方法的时候,会执行下面这样的操作步骤.

    • 如果在原型链上存在一个名为P的只读属性(只读的数据属性或者没有setter的访问器属性),则拒绝.
    • 如果在原型链上存在一个名为P的且拥有setter的访问器属性:则调用这个setter.
    • 如果没有名为P的自身属性:则如果这个对象是可扩展的,就使用下面的操作创建一个新属性:
      this.[[DefineOwnProperty]](
          P,
          {
              value: Value,
              writable: true,
              enumerable: true,
              configurable: true    },    Throw)
      否则,如果这个对象是不可扩展的,则拒绝.
    • 否则, 如果已经存在一个可写的名为P的自身属性.则调用:
      this.[[DefineOwnProperty]](P, { value: Value }, Throw)
      该操作只会更改P属性的值,其他的特性(比如可枚举性)都不会改变.

    赋值运算符(=)就是在调用[[Put]].比如:

    obj.prop = v;

    在引擎内部,会转换成这样的方法调用:

    obj.[[Put]]("prop", v, isStrictModeOn)

    isStrictModeOn对应着参数Throw.也就是说,赋值运算符只有在严格模式下才有可能抛出异常.[[Put]]没有返回值,但赋值运算符有.

    4. 作用及影响

    本节讲一下属性的定义操作和赋值操作各自的作用及影响.

    4.1. 赋值可能会调用原型上的setter,定义会创建一个自身属性

    给定一个空对象obj,他的原型proto有一个名为foo的访问器属性.

    var proto = {
        get foo() {
            console.log("Getter"); return "a";
        },
        set foo(x) {
            console.log("Setter: "+x);
        },
    }; var obj = Object.create(proto);

    那么,"在obj身上定义一个foo属性"和"为obj的foo属性赋值"有什么区别呢?

    如果是定义操作的话,则会在obj身上添加一个自身属性foo:

    > Object.defineProperty(obj, "foo", { value: "b" }); > obj.foo 'b'
    > proto.foo
    Getter 'a'

    但如果为foo属性赋值的话,则意味着你是想改变某个已经存在的属性的值.所以这次赋值操作会转交给原型proto的foo属性的setter访问器来处理,下面代码的执行结果就能证明这一结论:

    > obj.foo = "b";
    Setter: b 'b'

    你还可以定义一个只读的访问器属性,办法是:只定义一个getter,省略setter.下面的例子中,proto2的bar属性就是这样的只读属性,obj2继承了这个属性.

    "use strict"; var proto2 = {
        get bar() {
            console.log("Getter"); return "a";
        },
    }; var obj2 = Object.create(proto2);

    开启严格模式的话,下面的赋值操作会抛出异常.非严格模式的话,赋值操作只会静默失败(不起任何作用,也不报错).

    > obj2.bar = "b";
    TypeError: obj.bar is read-only

    我们可以定义一个自身属性bar,遮蔽从原型上继承的bar属性:

    > Object.defineProperty(obj2, "bar", { value: "b" }); > obj2.bar 'b'
    > proto2.bar
    Getter 'a'

    4.2. 原型链中的同名只读属性可能会阻止赋值操作,但不会阻止定义操作

    如果原型链中存在一个同名的只读属性,则无法通过赋值的方式在原对象上添加这个自身属性,必须使用定义操作才可以.这项限制是在ECMAScript 5.1中引入的:

    "use strict"; var proto = Object.defineProperties(
        {},
        {
            foo: { // foo属性的特性: value: "a",
                writable: false,  // 只读 configurable: true// 可配置        }
        }); var obj = Object.create(proto);

    赋值.赋值操作会导致异常:

    > obj.foo = "b";                 //译者注:貌似只有Firefox遵循了这个标准TypeError: obj.foo is read-only

    这貌似是个很奇怪的表现,原型上的属性居然可以影响到能否创建一个同名的自身属性 [3].但是这样的表现是有道理的,因为另外一种形式的只读属性(只有getter的访问器属性)也是这样的表现,这样才能统一.

    定义.通过定义的方式,我们可以成功创建一个新的自身属性:

    > Object.defineProperty(obj, "foo", { value: "b" }); > obj.foo 'b'
    > proto.foo 'a'

    4.3.  赋值运算符不会改变原型链上的属性

    执行下面的代码,则obj会从proto上继承到foo属性.

    var proto = { foo: "a" }; var obj = Object.create(proto);

    你不能通过为obj.foo赋值来改变proto.foo的值.这种操作只会在obj上新建一个自身属性:

    > obj.foo = "b"; 'b'
    > obj.foo 'b'
    > proto.foo 'a'

    4.4. 只有通过定义操作,才能创建一个拥有指定特性的属性

    如果通过赋值操作创建了一个自身属性,则该属性始终拥有默认的特性.如果你想指定某个特性的值,必须通过定义操作.

    4.5. 对象字面量中的属性是通过定义操作添加的

    下面的代码将变量obj指向了一个对象字面量:

    var obj = {
        foo: 123};

    这样的语句在引擎内部,可能会被转换成下面两种操作方式中的一种.首先可能是赋值操作:

    var obj = new Object();
    obj.foo = 123;

    其次,可能是个定义操作:

    var obj = new Object();
    Object.defineProperties(obj, {
        foo: {
            value: 123,
            enumerable: true,
            configurable: true,
            writable: true    }});

    到底是哪种呢?正确答案是第二种,因为第二种操作方式能够更好的表达出对象字面量的语义:创建新的属性.Object.create接受一个属性描述符作为第二个可选参数,也是这个原因.

    4.6. 方法属性

    可以通过定义操作新建一个只读的方法属性:

    "use strict"; function Stack() {
    }
    Object.defineProperties(Stack.prototype, {
        push: {
            writable: false,
            configurable: true,
            value: function (x) { /* ... */ }
        }
    });

    目的是为了防止在实例身上发生意外的赋值操作:

    > var s = new Stack(); > s.push = 5;
    TypeError: s.push is read-only

    不过,由于push是可配置的,所以我们仍可以通过定义操作来为实例添加一个自身的push方法.

    > var s = new Stack(); > Object.defineProperty(s, "push",
          { value: function () { return "yes" }}) > s.push() 'yes'

    我们甚至可以通过定义操作来重新定义原型上的push方法:Stack.prototype.push.

    5. 结论

    我们经常会通过为属性赋值来给一个对象添加新的属性.本文解释了这样做是可能引发一些问题的.因此,最好要遵循下面的规则:

    1. 如果你想创建一个新属性,则使用属性定义.
    2. 如果你想该变一个属性的值,则使用属性赋值.

    在评论中,medikoo提醒了我们使用属性描述符来创建属性可能会有点慢.我就经常通过为属性赋值来创建新属性,因为这样很方便.值得高兴的是,ECMAScript.next也许会把属性的定义操作变的既快又方便:已经存在一个“定义属性的运算符”的提案,可以作为Object.defineProperties的替代用法.由于属性定义和属性赋值之间的差别既很微妙,又很重要,所以这种改进应该会很受欢迎.

    展开全文
  • 布局: LinearLayout:线性布局(常用),让控件线性方向上依次排列。 RelativeLayout:相对布局(常用),通过相对定位的方式让控件出现布局的任何位置。 FrameLayout:框架布局...引入布局:   控件:

    布局:

    LinearLayout:线性布局(常用),让控件在线性方向上依次排列。

    RelativeLayout:相对布局(常用),通过相对定位的方式让控件出现在布局的任何位置。

    FrameLayout:框架布局(不太常用),所有的控件都放在布局的左上角。

    TableLayout:表格布局(不太常用),用表格的方式排列控件。

    <TableRow> </TableRow>在这里面编辑一个控件。

     

    引入布局:

    <include layout=”@layout/layout_name” />

     

    控件:

    Button:按钮。

    ImageButton:图片按钮,通常与android:background属性一起使用。

    TextView:文本显示框。

    EditText:文本输入框。

    ImageView:图片显示框。

    ProgressBar:进度条。

    ListView:列表。

    WebViewAbsoluteLayout的子类控件,浏览器控件,通过这个控件可以直接访问网页。

    Spinner:下拉列表。

    CheckBox:多项可选框。

    RadioRroup:单项选择控件。

    DatePicker:日期选择器。

    TimePicker:时间选择器。

    ScrollView:滚动视图控件,在线性布局外增加这个标记。

    RatingBar:评分控件。

    ImageSwitcher:显示列表图片中的单个大图;

    Gallery:显示列表图片中的小图列表索引。

     

     

    属性:

    android:id 给当前控件定义一个唯一标识符。

    android:layout_width  指定控件的宽度;android:layout_height  指定控件的高度。Android中所有的控件都有这两个属性,可选的值有三个:match_parent/fill_parent,后者很少用了,表示当前控件的大小和父布局的大小一样;wrap_content,表示当前控件的大小刚好可以包含住里面的内容。

    android:gravity  用来指定文字的对齐方式,值有topbottomleftrightcenter等,可以用“|”同时指定多个值。center等同于center_vertical|center_horizontal

    android:layout_gravity  用来指定控件在布局中的对齐方式,值同上。

    android:textSize  用来指定文字的大小(sp)。

    android:textColor  用来指定文字的颜色(#ffffffRGB

    android:hint=”string”  用来指定一段提示性的文本。

    android:maxLines=”figure” 用来指定输入文本的最大行数。

    android:src  用来为ImageView指定图片。

    android:visibility  控件的可见属性,值有三个:visible,表示控件是可见的;invisible表示控件时不可见的,但是却占有原来的位置;gone表示控件是不可见的,也不占用原来的位置。也可以在代码中使用m.setVisibility()方法指定可见性,值为:View.VISIBLEView.INVISIBLEView.GONE

    style=”?android:attr/controlName+Style+horizontal”  用来指定控件(如:进度条)的风格属性。

    android:max=”figure”  用来指定进度条的最大值。

    android:orientation=”vertical/horizontal”  用来为线性布局设置排列方向。

    android:layout_weight  表示控件在布局中的权重,即所占空间比例。

    android:layout_alignParentTop=”booleam”  与父布局上对齐;……;android:layout_centerInParent  与父布局中央对齐。

    android:layout_above=”@+id/control_id”  表示让一个控件位于另一个控件的上方(layout_below)。

    android:layout_toRightOf=”@+id/control_id”  表示让一个控件位于另一个控件的右侧(layout_toLeftOf)。

    android:layout_alignLeft=”@+id/control_id”  表示让一个控件的左边缘和另一个控件的左边缘对齐(layout_alignRightlayout_alignToplayout_alignBottom)。

    android:text=”string”  控件显示在界面上的文字(如Button控件)。

    android:inputType=”textPassword”  将输入框指定为密码输入框。

    android:layout_span=”figure”  表示控件占据的列数。

    android:androidstretchColumns=”1”  在表格布局中,表示如果控件不能占满屏幕宽度就将第二列进行拉伸,从0开始,0表示第一列,以此类推;可以用“,”隔开,输入多列。  

    android:layout_marginLeft=”figure+dip”  表示控件距离布局的左侧距离。

    android:divider=”#0000”  用来指定 ListView分隔线的颜色,这里表示是透明色。

    android:background  用来设置背景,值可以是颜色,也可以是图片。

    android:layout_x=”figure+dip”  绝对布局中设置位置(androidlayout_y)。

    android:textStyle  文字风格,值有:bolditalic等。

    android:progress=”50”  圆形进度条进度值。

    android:secondaryProgress  水平进度条进度值。

    android:numStars=”figure”  评分控件的总级别,总分,星星个数。

    android:rating=”1.5”  评分控件的当前级别,分数,星星个数。

    android:spacing=”figure+dp”  Gallery控件中图片之间的距离。

    展开全文
  • CSS 边框 border属性

    千次阅读 2018-02-16 22:12:27
    边框CSS1,就支持为元素添加边框,并可以设置边框的样式、颜色、及粗细。不过,当时的边框太过单一,只支持简单的线条...线条边框使用 border属性定义,图像边框使用 border-image 属性来定义,圆角边框使用 bo...
  • ES6 (Class)基本用法和静态属性+方法详解

    万次阅读 多人点赞 2016-12-20 10:37:05
    JavaScript语言的传统方法是通过构造函数,定义并生成新对象,prototype 属性使您有能力向对象添加属性和方法。下面是通过传统的方式创建和使用对象的案例: //Person.js function Person(x,y){ this
  • 分类解决类别不平衡问题

    万次阅读 多人点赞 2018-05-11 22:19:31
    关注微信公众号【Microstrong】,我现在研究方向是机器学习、深度学习,分享我学习过程的读书笔记!一起来学习,一起来交流,一起来进步吧!本文同步更新我的微信公众号里面,公众号文章地址:...
  • 与类图 1) (Class)封装了数据和行为,...一个可以有多种职责,设计得好的一般只有一种职责,在定义类的时候,将的职责分解成为属性和操作(即方法)。 3) 属性的数据职责,的操作即的行为
  • 上篇博文学习讲解了Class文件结构的有关知识点,关于数据项方面介绍了常量池,此篇文章将介绍完余下的数据项部分,大致知识点如下: 访问标志、索引、父类索引与接口索引集合、字段表集合、属性表集合 、各...
  • 慕课北京大学.软件工程.第八章.UML-1.表达客观事物的术语—类0 目录8 UML-18.3 表达客观事物的术语—类8.3.1课堂重点8.3.2...1单选(2分)在类属性定义中引入可见性,主要是为了支持_____这一软件设计原则。 A.抽象...
  • 相关文章 Android开发之Frame动画(帧动画) Android开发之Tween(补间动画)完全解析(上)——xml文件配置的实现 Android开发之Tween(补间动画)完全解析(下)——代码实现Hello,大家好,今天又来...Tween动画的讨论
  • 目录 1 线程上下文加载器 2 何时使用Thread.getContextClassLoader()? 3 加载器与Web容器 4 加载器与OSGi ...1 线程上下文加载器 ... java.lang.Thread的方法 getContextClassLoader()和 se...
  • 机器学习(概述一)——定义

    千次阅读 2019-05-28 16:18:17
    标称型目标变量的结果只有限目标集中取值,如真与假、动物分类集合 { 爬行、鱼类、哺乳、两栖 } ;数值型目标变量则可以从无限的数值集合取值,如 0.100、42.001、1000.743 等。数值型目标变量主要用于...
  • Clang属性

    千次阅读 2018-08-11 22:04:51
    功能属性 #pragma omp declare simd #pragma omp声明目标 _Noreturn abi_tag(gnu :: abi_tag) acquire_capability(acquire_shared_capability,clang :: acquire_capability,clang :: acquire_shared_...
  • 上一篇分析了什么是,并例举了一些例子,这里继续对进行分析和讲解。 一、定义形式 类定义的一般形式如下 [类定义修饰符] class  { //体  [成员变量声明] [构造函数]  [成员方法] } ...
  • Android动画之视图动画和属性动画

    千次阅读 2016-05-13 16:19:37
    View Animation视图动画是Android最基础的动画,API 1就已经加入,不需考虑兼容,但由于其动画只是作用于视图上,而不会由该控件的属性,所以有很多的局限。视图动画的基类是Animation其下
  • 由 于多道程序系统所带来的复杂环境,程序本身有了并行【为了充分利用资源,主存同时存放多道作业运行,所以各作业之间是并行的】、制约【各程序由于 同时存在于主存,因此他们之间会存在着相互依赖、相互...
  • java阿里巴巴规范提示:方法【xxxx】需要Transactional注解指定rollbackFor或者方法显示的rollback。先来看看异常的分类error是一定会回滚的这里Exception是异常,他又分为运行时异常RuntimeException和非运行...
  • static对象如果出现在类中,那么该对象即使从未被使用到,它也会被构造以及析构。而函数的static对象,如果该函数从未被调用,这个对象也就绝不会诞生,但是在函数每次被调用时检查对象是否需要诞生。 下面详细...
  • android menu的属性详细解释

    千次阅读 2014-11-20 10:42:07
    定义了一个菜单组(它是一个具有共同特征的菜单项的组合,如菜单项的可见性、可用性或可复选性)。它要包含多个元素,而且必须是元素的子元素。  属性(ATTRIBUTES):  android:id  资源ID。它...
  • 90年代初,Microsoft为Web程序员提供的 Active Server Pages(ASP)革命地改变了Web的编程。它可以利用十分易用的模型Web服务器上动态生成HTML,并且很容易的实现了对数据库的访问,就当时来说,这是一项多么...
  • 转载自:http://www.cnblogs.com/berry/articles/1582702.html 参考:... (一)inline函数(摘自C++ Primer的第三版) 函数声明或定义中函数返回类型前加上关键字inline即把min()指定
  • ConstraintLayout 属性详解 和Chain的使用

    万次阅读 多人点赞 2017-05-24 18:04:09
    另外 虽然大部分操作可以“Design”区域完成,但是保不齐的需要你切换至“Text”区域,写上一两行属性代码,了解 这些属性 总是有益无害的。 而且,有一些属性是无法简单通过拖拽点击完成的,例如 Margins when ...
  • 设计时属性:设计时属性相关类型

    千次阅读 2010-05-20 17:57:00
    控制范围广泛,比如可以控制该属性在属性窗口的显示模式,如:是否在属性窗口显示该属性,也可以指定此属性必须接收值类型描述,按组分类等,也可以控制文本的标记呈现格式等,甚至可以自己定义一个属性类,实现...
  • css3的部分属性

    千次阅读 2016-05-30 20:42:12
    1、阴影box-shadow:x轴偏移量 y轴偏移量 [阴影模糊半径] [阴影扩展半径] [阴影颜色] [投影方式...正值表示对象的底部,负值表示对象的顶部。 .boxshadow-outset{  width:100px; height:100px;  box-shadow:4px 4p
  • 声明:本文档仅为个人学习过程顺手翻译之作,方便开发的同胞借鉴参考。如有觉得译的不好不到位的地方,欢迎指正,将及时做出更正 尽量尊重原文档,因为首次Objective-C,有些地方可能直译了没有注意该语言的专有词...
  • UML图中类之间的关系

    万次阅读 2018-01-11 19:09:18
    UML图中类之间的关系:依赖,泛化,关联,聚合,组合,实现 与类图 1) (Class)封装了数据和行为,是面向...一个可以有多种职责,设计得好的一般只有一种职责,在定义类的时候,将的职责分解成为属性和操

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 70,320
精华内容 28,128
关键字:

在类的属性定义中引入可见性