精华内容
下载资源
问答
  • Java类和对象 详解(一)

    万次阅读 多人点赞 2016-10-06 20:48:02
    几乎现在的所有应用都以面向对象为主了,最早的面向对象的概念实际上是由IBM提出的,在70年代的Smaltalk语言之中进行了应用,后来根据面向对象的设计思路,才形成C++,而由C++产生了Java这门面向对象的编程语言。...

    一、面向对象简述

    面向对象是一种现在最为流行的程序设计方法,几乎现在的所有应用都以面向对象为主了,最早的面向对象的概念实际上是由IBM提出的,在70年代的Smaltalk语言之中进行了应用,后来根据面向对象的设计思路,才形成C++,而由C++产生了Java这门面向对象的编程语言。

    但是在面向对象设计之前,广泛采用的是面向过程,面向过程只是针对于自己来解决问题。面向过程的操作是以程序的基本功能实现为主,实现之后就完成了,也不考虑修改的可能性,面向对象,更多的是要进行子模块化的设计,每一个模块都需要单独存在,并且可以被重复利用,所以,面向对象的开发更像是一个具备标准的开发模式。

    在面向对象定义之中,也规定了一些基本的特征:
    (1)封装:保护内部的操作不被破坏;
    (2)继承:在原本的基础之上继续进行扩充;
    (3)多态:在一个指定的范围之内进行概念的转换。

    对于面向对象的开发来讲也分为三个过程:OOA(面向对象分析)、OOD(面向对象设计)、OOP(面向对象编程)。

    二、类与对象的基本概念

    类与对象时整个面向对象中最基础的组成单元。

    :是抽象的概念集合,表示的是一个共性的产物,类之中定义的是属性和行为(方法);
    对象:对象是一种个性的表示,表示一个独立的个体,每个对象拥有自己独立的属性,依靠属性来区分不同对象。

    可以一句话来总结出类和对象的区别:类是对象的模板,对象是类的实例。类只有通过对象才可以使用,而在开发之中应该先产生类,之后再产生对象。类不能直接使用,对象是可以直接使用的。

    三、类与对象的定义和使用

    在Java中定义类,使用关键字class完成。语法如下:

    class 类名称 {
             属性 (变量) ;
             行为 (方法) ;
    }

    范例:定义一个Person类

    class Person {     // 类名称首字母大写
        String name ;
        int age ;
        public void tell() {        // 没有static
              System.out.println("姓名:" + name + ",年龄:" + age) ;
             }
    }

    类定义完成之后,肯定无法直接使用。如果要使用,必须依靠对象,那么由于类属于引用数据类型,所以对象的产生格式(两种格式)如下:

    (1)格式一:声明并实例化对象

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

    (2)格式二:先声明对象,然后实例化对象:

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

    引用数据类型与基本数据类型最大的不同在于:引用数据类型需要内存的分配和使用。所以,关键字new的主要功能就是分配内存空间,也就是说,只要使用引用数据类型,就要使用关键字new来分配内存空间。

    当一个实例化对象产生之后,可以按照如下的方式进行类的操作:
    对象.属性:表示调用类之中的属性;
    对象.方法():表示调用类之中的方法。

    范例:使用对象操作类

    package com.wz.classandobj;
    
    class Person { 
        String name ;
        int age ;
        public void get() {
            System.out.println("姓名:" + name + ",年龄:" + age);
        }
    }
    
    public class TestDemo {
            public static void main(String args[]) {
                Person per = new Person() ;// 声明并实例化对象
                per.name = "张三" ;//操作属性内容
                per.age = 30 ;//操作属性内容
                per.get() ;//调用类中的get()方法
            }
    }

    运行结果:

    姓名:张三,年龄:30

    以上完成了一个类和对象的操作关系,下面换另外一个操作来观察一下:

    package com.wz.classandobj;
    
    class Person { 
        String name ;
        int age ;
        public void get() {
            System.out.println("姓名:" + name + ",年龄:" + age);
        }
    }
    
    public class TestDemo {
            public static void main(String args[]) {
                Person per = null;//声明对象
                per = new Person() ;//实例化对象
                per.name = "张三" ;//操作属性内容
                per.age = 30 ;//操作属性内容
                per.get() ;//调用类中的get()方法
            }
    }

    运行结果:

    姓名:张三,年龄:30

    那么,问题来了,以上两种不同的实例化方式有什么区别呢?
    我们从内存的角度分析。首先,给出两种内存空间的概念:
    (1)堆内存:保存对象的属性内容。堆内存需要用new关键字来分配空间;
    (2)栈内存:保存的是堆内存的地址(在这里为了分析方便,可以简单理解为栈内存保存的是对象的名字)。

    1

    任何情况下,只要看见关键字new,都表示要分配新的堆内存空间,一旦堆内存空间分配了,里面就会有类中定义的属性,并且属性内容都是其对应数据类型的默认值。

    于是,上面两种对象实例化对象方式内存表示如下:
    这里写图片描述

    两种方式的区别在于①②,第一种声明并实例化的方式实际就是①②组合在一起,而第二种先声明然后实例化是把①和②分步骤来。

    另外,如果使用了没有实例化的对象,结果如何?
    如下:

    package com.wz.classandobj;
    
    class Person { 
        String name ;
        int age ;
        public void get() {
            System.out.println("姓名:" + name + ",年龄:" + age);
        }
    }
    
    public class TestDemo {
            public static void main(String args[]) {
                Person per = null;//声明对象
                //per = new Person() ;//实例化对象
                per.name = "张三" ;//操作属性内容
                per.age = 30 ;//操作属性内容
                per.get() ;//调用类中的get()方法
            }
    }

    运行结果:

    Exception in thread "main" java.lang.NullPointerException
        at com.wz.classandobj.TestDemo.main(TestDemo.java:15)

    此时,程序只声明了Person对象,但并没有实例化Person对象(只有了栈内存,并没有对应的堆内存空间),则程序在编译的时候不会出现任何的错误,但是在执行的时候出现了上面的错误信息。这个错误信息表示的是“NullPointerException(空指向异常)”,这种异常只要是应用数据类型都有可能出现。

    四、对象引用传递初步分析

    引用传递的精髓:同一块堆内存空间,可以同时被多个栈内存所指向,不同的栈可以修改同一块堆内存的内容。

    下面通过若干个程序,以及程序的内存分配图,来进行代码的讲解。

    我们来看一个范例:

    class Person {     
             String name ;
             int age ;
             public void tell() {        
                       System.out.println("姓名:" + name + ",年龄:" + age) ;
             }
    }
    public class TestDemo {
             public static void main(String args[]) {
                       Person per1 = new Person() ;         // 声明并实例化对象
                       per1.name = "张三" ;
                       per1.age = 20 ;
                       Person per2 = per1 ;  // 引用传递
                       per2.name = "李四" ;
                       per1.tell() ;
             }
    }

    对应的内存分配图如下:

    11

    再来看另外一个:

    class Person {
             String name ;
             int age ;
             public void tell() {
                       System.out.println("姓名:" + name + ",年龄:" + age) ;
             }
    }
    public class TestDemo {
             public static void main(String args[]) {
                       Person per1 = new Person() ;         // 声明并实例化对象
                       Person per2 = new Person() ;
                       per1.name = "张三" ;
                       per1.age = 20 ;
                       per2.name = "李四" ;
                       per2.age = 30 ;
                       per2 = per1 ;// 引用传递
                       per2.name = "王五" ;
                       per1.tell() ;
             }
    }

    对应的内存分配图如下:
    12

    垃圾:指的是在程序开发之中没有任何对象所指向的一块堆内存空间,这块空间就成为垃圾,所有的垃圾将等待GC(垃圾收集器)不定期的进行回收与空间的释放。

    未完待续。。。

    展开全文
  • POJO对象和Java类对象区别和联系是什么 POJO对象和Java类对象区别和联系是什么
  • 怎么来理解java类和对象区别

    千次阅读 多人点赞 2018-05-08 11:29:19
    对象在需求中的使用在具体问题中如何使用面向对象去分析问题,如何使用面向对象。以把大象装冰箱为例进行分析:在针对具体的需求,可以使用名词提炼的办法进行分析,寻找具体的对象。需求:把大象装冰箱里对象:...

    对象在需求中的使用

    在具体问题中如何使用面向对象去分析问题,和如何使用面向对象。

    以把大象装冰箱为例进行分析:

    在针对具体的需求,可以使用名词提炼的办法进行分析,寻找具体的对象。
    需求:把大象装冰箱里
    对象:大象、冰箱
    分三步:
        1、打开冰箱门
        2、将大象装进去
        3、关闭冰箱门
    分析发现打开、装、关闭都是冰箱的功能。即冰箱对象具备如下功能:
        1)冰箱打开
        2)冰箱存储
        3)冰箱关闭
    用伪代码描述,上述需求中有两个具体的事物 大象 和  冰箱
    描述大象:
        class 大象
            {
            }
    描述冰箱
        class冰箱
            {
                void 打开(){}
                void 存储(大象){}
                void 关闭(){}
            }
    当把具体的事物描述清楚之后,需要使用这些具体的事物,Java使用具体的事物,需要通过new关键字来创建这个事物的具体实例。
    使用对象:
        1、创建冰箱的对象
            冰箱 bx = new 冰箱();  
        2、调用冰箱的功能
            对象.功能();
            bx.打开();
            bx.存储(new 大象());
            bx.关闭();
    总结:
    1、先按照名词提炼问题领域中的对象
    2、对对象进行描述,其实就是在明确对象中应该具备的属性和功能
    3、通过new的方式就可以创建该事物的具体对象
    4、通过该对象调用它以后的功能。

    对象在代码中的体现

    在分析现实生活中的事物时发现,这些事物都有其具体的特点和功能,这些特点和功能就组成了这个特殊的事物。
    描述小汽车。
    分析:
    事物的特点(属性):
    颜色。
    轮胎个数。
    事物的(功能):
    运行。

    发现:事物其实就是由特点(属性)和行为(功能)组成的。
    可以简单理解:属性就是数值,其实就是变量;行为就是功能,就是方法。
    小汽车 {
    颜色;
    轮胎个数;
    运行() { }
    }
    通过计算机语言Java来描述这个事物。

    定义类的格式

    public class 类名 {
    	//可编写0至n个属性
        数据类型 变量名1;
        数据类型 变量名2;
    	
    	//可编写0至n个方法
    	修饰符 返回值类型 方法名(参数){
    		执行语句;
    }
    }
    

    汽车类

    public class Car {
    	String color;
    	int number;
    
    	void run() {
    		System.out.println(color + ":" + number);
    	}
    }
    
    通过代码的描述,知道类的真正意义就是在描述事物。属性和功能统称为事物中的成员。
    事物的成员分为两种:成员属性和成员功能。
    成员属性在代码中的体现就是成员变量
    成员功能在代码中的体现就是成员方法

    把写好的代码测试一下。需要一个可以独立运行类。

    创建对象的格式:

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

    测试类

    public class CarDemo {
    	public static void main(String[] args) { 
    		/*
    		 *  测试:Car类中的run方法。
    		 */
    		// 1,创建Car的对象。给对象起个名字。
    		Car c = new Car();// c是类类型的变量。c指向了一个具体的Car类型的对象。
    		// 2,通过已有的对象调用该对象的功能。格式:对象.对象成员;
    		// 3,可以该对象的属性赋值。
    		c.color = "red";
    		c.number = 4;
    		c.run();
    	}
    }
    

    类和对象的区别

    面向对象的编程思想力图在程序中对事物的描述与该事物在现实中的形态保持一致。为了做到这一点,面向对象的思想中提出两个概念,即类和对象。其中,类是对某一类事物的抽象描述,而对象用于表示现实中该类事物的个体。接下来通过一个图例来抽象描述类与对象的关系,如下图所示。


    在上图中,可以将玩具模型看作是一个类,将一个个玩具看作对象,从玩具模型和玩具之间的关系便可以看出类与对象之间的关系。类用于描述多个对象的共同特征,它是对象的模板。对象用于描述现实中的个体,它是类的实例。从上图中可以明显看出对象是根据类创建的,并且一个类可以对应多个对象,接下来分别讲解什么是类和对象。

    经过前面几个知识点的学习,基本上掌握了类是用于描述事物的,类中可以定义事物的属性和行为。而对象是通过描述的这个类,使用new关键字创建出来,通过对象就可以调用该对象具体的属性和功能了。

    局部变量和成员变量区别

    理解清楚了类和对象之后,发现在描述类的属性定义变量差别不大,唯一区别就是位置发生了改变,那么类中定义的变量,和在方法定义的变量有什么差别呢?总结下面几点异同
    区别一:定义的位置不同
        定义在类中的变量是成员变量
        定义在方法中或者{}语句里面的变量是局部变量
    区别二:在内存中的位置不同
        成员变量存储在对内存的对象中
        局部变量存储在栈内存的方法中
    区别三:声明周期不同
        成员变量随着对象的出现而出现在堆中,随着对象的消失而从堆中消失
        局部变量随着方法的运行而出现在栈中,随着方法的弹栈而消失
    区别四:初始化不同
        成员变量因为在堆内存中,所有默认的初始化值

        局部变量没有默认的初始化值,必须手动的给其赋值才可以使用。

    本文结。


    展开全文
  • Java类和对象 详解(二)

    万次阅读 多人点赞 2016-10-07 17:52:38
    上一篇Java类和对象 详解(一)讲解了类和对象的基本概念,定义使用,以及对象引用传递的初步分析,下面接着来讲其他内容。一、面向对象的封装性封装(encapsulation)又叫隐藏实现(Hiding the implementation)。...

    上一篇Java类和对象 详解(一)讲解了类和对象的基本概念,定义和使用,以及对象引用传递的初步分析,下面接着来讲其他内容。

    一、面向对象的封装性

    封装(encapsulation)又叫隐藏实现(Hiding the implementation)。就是只公开代码单元的对外接口,而隐藏其具体实现。比如手机,手机的键盘,屏幕,听筒等,就是其对外接口。你只需要知道如何按键就可以使用手机,而不需要了解手机内部的电路是如何工作的。封装机制就像手机一样只将对外接口暴露,而不需要用户去了解其内部实现。

    在研究封装性之前,我们先来看一段代码:

    package com.wz.classandobj;
    
    class Book{
    
        String title;
        double price;
    
        public void getInfo(){
            System.out.println("图书的名称:"+title+" 图书的价格:"+price);
        }
    }
    
    public class TestDemo {
            public static void main(String args[]) {
                Book book = new Book();
                book.title = "Java开发";
                book.price = -89.9;
                book.getInfo();
            }
    }

    运行结果:

    图书的名称:Java开发 图书的价格:-89.9

    以上代码没有任何语法错误,却存在一个业务逻辑的错误,因为图书的价格不能为负数。造成这种情况的的原因在于:对象可以在一个类的外部直接访问属性。
    如何解决?我们需要将Book类中的属性设置为对外不可见(只能是本类访问),可以使用private关键字来定义属性。

    修改之前的代码如下:

    package com.wz.classandobj;
    
    class Book{
    
        private String title;
        private double price;
    
        public void getInfo(){
            System.out.println("图书的名称:"+title+" 图书的价格:"+price);
        }
    }
    
    public class TestDemo {
            public static void main(String args[]) {
                Book book = new Book();
                book.title = "Java开发";
                book.price = -89.9;
                book.getInfo();
            }
    }

    运行:

    Exception in thread "main" java.lang.Error: Unresolved compilation problems: 
        The field Book.title is not visible
        The field Book.price is not visible
    
        at com.wz.classandobj.TestDemo.main(TestDemo.java:16)
    

    我们发现,在访问属性的时候,外部的对象无法再直接调用类中的属性了,此时就相当于Book类的属性对外部不可见。

    但是,要想让程序可以正常运行,那么必须让外部可以操作Book类的属性。在Java开发中,针对属性有这样的定义,在类中定义的属性都要求使用private声明,如果属性需要被外部所使用,那么按照要求,定义属性相应的setter和getter方法,以Book类中的String title 为例:
    (1)setter方法是设置属性内容:

    public void setTitle(String t)

    主要:有参数。

    (2)getter方法是取得属性内容:

    public String getTitle()

    注意:无参数。

    范例:为Book类的封装属性设置setter和getter。

    package com.wz.classandobj;
    
    class Book{
    
        private String title;
        private double price;
    
        public String getTitle() {
            return title;
        }
    
        public void setTitle(String title) {
            this.title = title;
        }
    
        public double getPrice() {
            return price;
        }
    
    
        public void setPrice(double price) {
            this.price = price;
        }
    
        public void getInfo(){
            System.out.println("图书的名称:"+title+" 图书的价格:"+price);
        }
    }
    
    public class TestDemo {
            public static void main(String args[]) {
                Book book = new Book();
                book.setTitle("Java开发"); 
                book.setPrice(-89.9);
                book.getInfo();
            }
    }

    运行结果:

    图书的名称:Java开发 图书的价格:-89.9
    

    发现,图书的价格是负数,需要加入检查业务逻辑错误的代码,可以在setter中增加验证,如果值为正,赋值,否则为默认值0.0:

        public void setPrice(double price) {
            if(price > 0.0){
                this.price = price;
            }
        }

    对于数据验证,在Java标准开发中应该由辅助代码完成。在实际开发中,setter往往只是简单的设置属性内容,getter只是简单的取得属性内容。

    开发建议:以后在定义类的时候,所有的属性都要编写private封装,封装之后的属性如果需要被外部操作,则编写setter、getter。

    二、类中的构造方法

    先来看对象的产生格式:

    ①类名称 ②对象名称 = ③new ④类名称();

    ①类名称:规定了对象的类型。即:对象可以使用哪些属性和方法都是由类定义的;
    ②对象名称:如果需要使用对象,需要有一个名称,这是一个唯一的标记;
    ③new:分配新的堆内存空间;
    ④类名称():调用了名称和类名称相同的方法,这就是构造方法。

    实际上,构造方法一直在被我们调用,但我们并没有去定义它,为什么能够使用呢?这是因为在整个Java开发中,为了保证程序可以正常执行,即便用户没有定义任何构造方法,也会在程序编译后自动为类增加一个没有参数,方法名称与类名称相同,没有返回值的构造方法。

    构造方法的定义:方法名称和类名称相同,没有返回值声明。

        //无参,无返回值的构造方法
        public Book() {
    
        }

    如果在Book类中没有定义以上的构造方法,那么也会自动生成一个无参,无返回值的构造方法。

    我们再看:

    package com.wz.classandobj;
    
    class Book{
    
        //无参,无返回值的构造方法
        public Book() {
            System.out.println("无参构造方法");
        }
    
    }
    
    public class TestDemo {
            public static void main(String args[]) {
                Book book = null;//声明对象
            }
    }

    运行,什么也没有打印。
    在主方法中加入实例化对象的代码:

    public class TestDemo {
            public static void main(String args[]) {
                Book book = null;//声明对象
                book = new Book();//实例化对象
            }
    }

    运行:

    无参构造方法

    以上说明,构造方法是在对象使用关键字new实例化的时候被调用

    构造方法与普通方法最大的区别是:
    构造方法在实例化对象(new)的时候只调用一次,而普通方法是在实例化对象之后可以随意调用多次。

    在实际开发中,构造方法的作用是在类对象实例化的时候设置属性的初始化内容,范例如下:

    package com.wz.classandobj;
    
    class Book{
    
        private String title;
        private double price;
    
        public Book(String title, double price) {
            this.title = title;
            this.price = price;
        }
    
        public String getTitle() {
            return title;
        }
    
        public void setTitle(String title) {
            this.title = title;
        }
    
        public double getPrice() {
            return price;
        }
    
    
        public void setPrice(double price) {
            this.price = price;
        }
    
        public void getInfo(){
            System.out.println("图书的名称:"+title+" 图书的价格:"+price);
        }
    }
    
    public class TestDemo {
            public static void main(String args[]) {
                Book book = new Book("Java开发",89.9);//设置属性的初始化内容
                book.getInfo();
    
            }
    }

    运行结果:

    图书的名称:Java开发 图书的价格:89.9

    如果一个类中已经明确定义了一个构造方法,则无参构造方法将不会自动生成。而且,一个类之中至少存在一个构造方法。另外,既然构造方法也属于方法,那么构造方法也可以重载,但是由于构造方法的特殊性,所以在构造方法重载时注意其参数的类型及参数的个数即可。

    范例如下:

    package com.wz.classandobj;
    
    class Book{
    
        private String title;
        private double price;
    
    
        public Book() {
            System.out.println("无参的构造方法");
        }
    
    
        public Book(String title) {
            this.title = title;
            System.out.println("有一个参数的构造方法");
        }
    
    
        public Book(String title, double price) {
            this.title = title;
            this.price = price;
            System.out.println("有俩个参数的构造方法");
        }
    
        public void getInfo(){
            System.out.println("图书的名称:"+title+" 图书的价格:"+price);
        }
    }
    
    public class TestDemo {
            public static void main(String args[]) {
                Book book1 = new Book();
                book1.getInfo();
    
                Book book2 = new Book("Java开发");
                book2.getInfo();
    
                Book book3 = new Book("Java开发",89.9);
                book3.getInfo();
    
            }
    }

    运行结果:

    无参的构造方法
    图书的名称:null 图书的价格:0.0
    有一个参数的构造方法
    图书的名称:Java开发 图书的价格:0.0
    有俩个参数的构造方法
    图书的名称:Java开发 图书的价格:89.9
    

    在进行构造方法重载时有一个编写建议:所有重载的构造方法按照参数的个数由多到少,或者是由少到多排列。

    我们再来看,如果在类中为属性直接设置默认值,结果会怎样?

    package com.wz.classandobj;
    
    class Book{
    
        private String title = "Android开发";
        private double price = 199.9;
    
    
        public Book() {
            System.out.println("无参的构造方法");
        }
    
    
        public Book(String title) {
            this.title = title;
            System.out.println("有一个参数的构造方法");
        }
    
    
        public Book(String title, double price) {
            this.title = title;
            this.price = price;
            System.out.println("有俩个参数的构造方法");
        }
    
        public void getInfo(){
            System.out.println("图书的名称:"+title+" 图书的价格:"+price);
        }
    }
    
    public class TestDemo {
            public static void main(String args[]) {
                Book book1 = new Book();
                book1.getInfo();
    
                Book book2 = new Book("Java开发");
                book2.getInfo();
    
                Book book3 = new Book("Java开发",89.9);
                book3.getInfo();
    
            }
    }

    运行结果:

    无参的构造方法
    图书的名称:Android开发 图书的价格:199.9
    有一个参数的构造方法
    图书的名称:Java开发 图书的价格:199.9
    有俩个参数的构造方法
    图书的名称:Java开发 图书的价格:89.9
    

    从上面可以发现:如果在类中为属性直接设置默认值,而且这个默认值是在构造方法执行完后才会设置的,且属性内容为对应数据类型的默认值时才设置类中定义的这个默认值。但是,要注意的是在构造方法没有执行之前,属性内容都是其对应数据类型的默认值。

    三、类中的匿名对象

    没名字的对象称为匿名对象,对象的名字按照之前的内存关系来讲,在栈内存之中,而对象的具体内容在堆内存之中保存,这样,没有栈内存指向堆内存空间,就是一个匿名对象。

    范例:

    package com.wz.classandobj;
    
    class Book{
    
        private String title;
        private double price;
    
        public Book(String title, double price) {
            this.title = title;
            this.price = price;
            System.out.println("有俩个参数的构造方法");
        }
    
        public void getInfo(){
            System.out.println("图书的名称:"+title+" 图书的价格:"+price);
        }
    }
    
    public class TestDemo {
            public static void main(String args[]) {
                //匿名对象
                new Book("Java开发",89.9).getInfo();
    
            }
    }

    运行结果:

    有俩个参数的构造方法
    图书的名称:Java开发 图书的价格:89.9

    匿名对象由于没有对应的栈内存指向,所以只能使用一次,一次之后就将成为垃圾,并且等待被GC回收释放。

    展开全文
  • java对象的指针有神马区别和联系 java对象的指针有神马区别和联系
  • 透彻理解 Java synchronized 对象和类锁的区别

    万次阅读 多人点赞 2017-02-17 14:34:05
    synchronized 加到 static 方法...对象和类锁是不同的锁,所以多个线程同时执行这2个不同锁的方法时,是异步的。 在Task2 中定义三个方法 doLongTimeTaskAdoLongTimeTaskB是锁,而doLongTimeTaskC是对象锁。pub

    synchronized 加到 static 方法前面是给class 加锁,即类锁;而synchronized 加到非静态方法前面是给对象上锁。这两者的区别我用代码来演示下:

    1. 对象锁和类锁是不同的锁,所以多个线程同时执行这2个不同锁的方法时,是异步的。

    在Task2 中定义三个方法 doLongTimeTaskA和doLongTimeTaskB是类锁,而doLongTimeTaskC是对象锁。

    public class Task2 {
    
        public synchronized static void doLongTimeTaskA() {
            System.out.println("name = " + Thread.currentThread().getName() + ", begain");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.println("name = " + Thread.currentThread().getName() + ", end");
        }
    
        public synchronized static void doLongTimeTaskB() {
            System.out.println("name = " + Thread.currentThread().getName() + ", begain");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.println("name = " + Thread.currentThread().getName() + ", end");
        }
    
        public synchronized void doLongTimeTaskC() {
    
            System.out.println("name = " + Thread.currentThread().getName() + ", begain");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.println("name = " + Thread.currentThread().getName() + ", end");
    
        }
    

    三个线程的代码如下:

    class ThreadA extends Thread{
        
        private Task2 mTask2;
        
        public ThreadA(Task2 tk){
            mTask2 = tk;
        }
        
        public void run() {
            mTask2.doLongTimeTaskA();
        }
    }
    
    class ThreadB extends Thread{
        
        private Task2 mTask2;
        
        public ThreadB(Task2 tk){
            mTask2 = tk;
        }
        
        public void run() {
            mTask2.doLongTimeTaskB();
        }
    }
    
    class ThreadC extends Thread{
        
        private Task2 mTask2;
        
        public ThreadC(Task2 tk){
            mTask2 = tk;
        }
        
        public void run() {
            mTask2.doLongTimeTaskC();
        }
    }
    

    main函数中执行代码如下:

            Task2 mTask2 = new Task2();
            ThreadA ta = new ThreadA(mTask2);
            ThreadB tb = new ThreadB(mTask2);
            ThreadC tc = new ThreadC(mTask2);
            
            ta.setName("A");
            tb.setName("B");
            tc.setName("C");
            
            ta.start();
            tb.start();
            tc.start();
    

    执行的结果如下:

    name = A, begain, time = 1487311199783
    name = C, begain, time = 1487311199783
    name = C, end, time = 1487311200784
    name = A, end, time = 1487311200784
    name = B, begain, time = 1487311200784
    name = B, end, time = 1487311201784
    

    可以看出由于 doLongTimeTaskA和doLongTimeTaskB都是类锁,即同一个锁,所以 A和B是按顺序执行,即同步的。而C是对象锁,和A/B不是同一种锁,所以C和A、B是 异步执行的。(A、B、C代指上面的3中方法)。

    我们知道对象锁要想保持同步执行,那么锁住的必须是同一个对象。下面就修改下上面的来证明:

    Task2.java不变,修改ThreadA 和 ThreadB 如下:

    class ThreadA extends Thread{
        
        private Task2 mTask2;
        
        public ThreadA(Task2 tk){
            mTask2 = tk;
        }
        
        public void run() {
            mTask2.doLongTimeTaskC();
        }
    }
    
    class ThreadB extends Thread{
        
        private Task2 mTask2;
        
        public ThreadB(Task2 tk){
            mTask2 = tk;
        }
        
        public void run() {
            mTask2.doLongTimeTaskC();
        }
    }
    

    main方法如下:

     Task2 mTaska = new Task2();
     Task2 mTaskb = new Task2();
     ThreadA ta = new ThreadA(mTaska );
     ThreadB tb = new ThreadB(mTaskb );
            
            
     ta.setName("A");
     tb.setName("B");
            
     ta.start();
     tb.start();
          
    

    结果如下:

    name = A, begain, time = 1487311905775
    name = B, begain, time = 1487311905775
    name = B, end, time = 1487311906775
    name = A, end, time = 1487311906775
    

    从结果看来,对象锁锁的对象不一样,分别是mTaska , mTaskb,所以线程A和线程B调用 doLongTimeTaskC 是异步执行的。

    但是,类锁可以对类的所有对象的实例起作用。只需修改ThradA
    和 ThreadB,main 方法不做改变,修改如下:

    class ThreadA extends Thread{
        
        private Task2 mTask2;
        
        public ThreadA(Task2 tk){
            mTask2 = tk;
        }
        
        public void run() {
            //mTask2.doLongTimeTaskC();
            mTask2.doLongTimeTaskA();
        }
    }
    
    class ThreadB extends Thread{
        
        private Task2 mTask2;
        
        public ThreadB(Task2 tk){
            mTask2 = tk;
        }
        
        public void run() {
           //mTask2.doLongTimeTaskC();
            mTask2.doLongTimeTaskA();
        }
    }
    

    结果如下:

    name = A, begain, time = 1487312239674
    name = A, end, time = 1487312240674
    name = B, begain, time = 1487312240674
    name = B, end, time = 1487312241674
    

    可以看出 在线程A执行完doLongTimeTaskA方法后,线程B才会获得该类锁接着去执行doLongTimeTaskA。也就是说,类锁对所有的该类对象都能起作用。

    总结:

    1. 如果多线程同时访问同一类的 类锁(synchronized 修饰的静态方法)以及对象锁(synchronized 修饰的非静态方法)这两个方法执行是异步的,原因:类锁和对象锁是2中不同的锁。
    2. 类锁对该类的所有对象都能起作用,而对象锁不能。

    以后文章会同步到个人公众号,欢迎关注交流
    在这里插入图片描述

    展开全文
  • java 对象和类锁的区别

    千次阅读 2017-09-18 15:19:32
    1.一个可以有多个对象,所以一个可以有多个对象锁。 2.当一个中有多个synchronized修饰的同步方法时,其中一个方法被线程访问持有锁,其他方法同样被锁住,其他线程依然不能访问其他同步方法,因为此时锁住的...
  • java接口与对象区别

    万次阅读 2017-11-21 08:35:57
    深入理解Java的接口抽象 对于面向对象编程来说,抽象是它的一大特征之一。在Java中,可以通过两种形式来体现OOP的抽象:接口抽象。这两者有太多相似的地方,又有太多不同的地方。很多人在初学的时候会以为...
  • javaScript中创建对象和Java创建对象区别

    千次阅读 多人点赞 2018-03-27 09:26:52
    Java和js创建对象区别
  • Java类和对象知识点的整理

    千次阅读 多人点赞 2019-04-14 18:00:01
    通过学习视频,特意写下此次博客。本次博客目的是为了...一、类和对象 1.面向对象 (1)面向对象的理解 面向对象是已对象为基础,完成各种操作主要强调对象。 (2)面向对象的特点 面向对象是一种常见的思想,...
  • java类和对象及python中的类似实现

    千次阅读 2018-12-10 13:49:00
    一:java类和对象 首先,我们简单说一下类和对象的理解:所有男的这相当于一个“类”,而某个具体的人就是一个“对象” 类:当做对象的模板 对象:根据类创建,在java中,使用关键词new创建新对象 java中定义一...
  • Java对象的概念区别

    千次阅读 2014-08-26 23:29:52
    Java是一种面向对象的程序设计语言(Object Oriented Programming:OOP),面向对象的程序设计语言中有类和对象的概念,它们在概念上有什么区别呢?  这往往是一个令面向对象的初学者感到迷惑的问题。    下面...
  • 1.对象的概念 :万物皆对象,... 的特点:对象的类型,具有相同属性方法的一组对象的集合 4。什么是对象的属性:属性,对象具有的各种特征 ,每个对象的每个属性都拥有特定值 5.什么事对象的方法:对象
  • java类和对象的生命周期

    万次阅读 多人点赞 2018-07-09 06:55:00
    Java 对象生命周期在JVM运行空间中,对象的整个生命周期大致可以分为7个阶段:创建阶段(Creation)、应用阶段(Using)、不可视阶段(Invisible)、不可到达阶段(Unreachable)、可收集阶段(Collected)、终结...
  • js的对象和java的简单区别

    千次阅读 2018-08-03 10:05:59
    js的继承等是通过原型链或其他方法进行实现的,es6的class本质上还是对象和java等的class还是不同的。 java是不可以直接运行的。 js的对象是可以直接调用运行的。这也就是基于对象的特点。 先写到这。  ....
  • Java对象的关系与区别

    千次阅读 2018-04-12 12:43:59
    什么是就是具备某些共同特征的实体的集合,它是一种抽象的数据类型,它是对所具有相同特征实体的抽象。在面向对象的程序设计语言中,是对一“事物...而对象的产生在Java中是使用new来实现的。做一个比方老...
  • Java类对象和实例的理解

    千次阅读 多人点赞 2017-11-29 20:50:42
    的引用、对象和实例
  • Java类方法与对象方法的区别

    千次阅读 2018-06-08 22:40:08
    通过两个 StaticDemo、KY4_1 来说明变量与对象变量,以及方法与对象方法的区别。class StaticDemo { static int x; static int y;//在int前加上static public static int getX() { return x; } public ...
  • 点击进入_更多_Java千百问1、接口抽象有什么区别Java语言中,抽象abstract class接口interface是抽象定义的两种机制。正是由于这两种机制的存在,才赋予了Java强大的面向对象能力。抽象abstract class...
  • java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁。线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。 获得内置锁的唯一途径就是进入这个锁的保护的...
  • c++类和java类的一些区别

    千次阅读 2018-10-06 22:34:18
    两者的区别,有些比较老的书上介绍,c++不允许在声明中初始化. 但是c++11已经允许在声明中进行初始化了 接下来讨论c++相对特殊的,const变量static变量以及引用的初始化. 考虑下面几种变量如何初始化的问题 ...
  • java对象和对象的引用的区别

    千次阅读 2017-09-25 00:01:32
     这段话来自于《Java编程思想》,很显然,从这段话可以看出对象和对象引用不是一回事,是两个完全不同的概念。举个例子,我们通常会用下面这一行代码来创建一个对象:  Person person = new Pe
  • Java反射】类对象

    千次阅读 2021-06-17 15:04:24
    要注意类对象和类的实例对象之间的区别。一个类可以有多个实例对象,但只能有一个类对象。 2 获取类对象的三种方式 2.1 准备实体类 People.java package study; public class People { private int id; private ...
  • Java类和对象 详解(一)(转载)

    千次阅读 2018-07-04 10:44:26
    几乎现在的所有应用都以面向对象为主了,最早的面向对象的概念实际上是由IBM提出的,在70年代的Smaltalk语言之中进行了应用,后来根据面向对象的设计思路,才形成C++,而由C++产生了Java这门面向对象的编程语言。...
  • Java中mutable对象和immutable对象区别

    万次阅读 2016-04-20 17:03:50
    今天读jdk源码中Map.java时看到一句话:“great care must be exercised if mutable objects are used as map keys”; 第一次知道mutable对象这个概念,google了一下,维基百科定义如下: “In object-oriented ...
  • JAVA Synchronized对象和类区别(牛逼)

    千次阅读 多人点赞 2019-01-03 18:48:03
    一个就像一个四合院,四合院的大门叫做构造方法,盖房子必须经过大门,每new一个对象,就表示在四合院里再盖一间新房子,大门上面的锁,叫做构造锁,里面每一间房子就是一个实例,每间房子里边都有一个锁叫做实例...
  • Java静态对象和非静态对象有什么区别?? 对于静态方法,相信它的作用在各位朋友眼里也是不容置疑的,那么他跟非静态到底有什么区别呢??? 到底有什么好处呢??对于静态方法来说~
  • 当我们使用java封装了一个实体时,该实体中,有一些变量函数。此时在该中的函数,我们可以称之为该实体的方法了,该实体中的变量,我们可以称之为该实体的属性。我们这里以一个Person实体为例。 ...
  • java对象 POJOJavaBean的区别

    万次阅读 多人点赞 2017-10-10 18:31:38
    "Plain Ordinary Java Object",简单普通的java对象。主要用来指代那些没有遵循特定的java对象模型,约定或者框架的...没有从任何继承、也没有实现任何接口,更没有被其它框架侵入的java对象。 public class BasicI
  • java对象的关系与区别

    万次阅读 多人点赞 2019-04-08 15:25:54
    类和对象区别  1,是一个抽象的概念,它不存在于现实中的时间/空间里,只是为所有的对象定义了抽象的属性与行为。就好像“Person(人)”这个,它虽然可以包含很多个体,但它本身不存在于现实世界上。 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 685,276
精华内容 274,110
关键字:

java类和对象的区别

java 订阅