• 《JAVA学习笔记(1---13-4)》


     【1】问题:
         1.什么叫做面向过程?    
         2.什么叫做面向对象?
    
    解答:
         1:    所谓的面向过程就是我们是一个执行者,我们要开发一个项目,这个项目要求要实现很多功能,作为执行者的我们就需要
            去一个一个的找这些功能,然后组装,最后形成一个产品。 此时的我们是站在执行者这个立场上的。
    
         2:    而所谓的面向对象呢,就是我们是站在指挥者这个立场上的。 首先(1)面向对象是一种符合人们思考习惯的思想
            (2)面向过程更多的体现的是执行者,在面向对象中更多的是体现指挥者,指挥对象做事情。(3)面向对象把复杂问
             简单化了。
    
            具体举例来说: 现在面试官您就是在以一种面向对象的思想在思考问题, 作为面试官,您本身就有开发能力,能开发
            项目。而为什么您还要招聘人呢? 这是因为当一个项目很繁杂,庞大的时候,一个人的时间精力毕竟是有限的,开发周期也很长
            为了提高效率,需要有更多具备专业开发能力的人来帮助您开发项目,这个人就是您所需的对象,只要调用该对象的开发功能
            就可以完成项目开发,通俗的说 只要指挥他们做事情就可以了。
    
        根据当时的环境氛围也可以举一些恰当的例子,还可以说一句很有哲理的话(万物皆对象),恰当的例子有当时桌子上的电脑 
        茶杯等。
    
    
    【2】问题:基本数据类型和引用数据类型有什么差别?
        
    答:基本数据类型和引用数据类型最大的差别就是基本数据类型里面存放了变量的值,而引用数据类型里面存放的是对象的首地址。
    
    【3】代码:implementation-ready
    
    【4】什么是类?什么是对象?类和对象之间有什么关系?
        类:对事物的描述。需要体现属性和行为。
        对象:该类事物创建的实例(实体),通过该对象调用具有的属性和行为。
        类和对象的关系:类是对象的抽象,对象是类的实例。
    
    【5】成员变量和局部变量的区别:
        区别一:定义的位置不同。
            成员变量定义在类中,
            局部变量定义在方法中及语句里。
    
        区别二:在内存中的位置不同。
            成员变量存储在堆内存的对象中。
            局部变量存储在栈内存的方法中。
    
        区别三:生命周期不同。
            成员变量随着对象的出现而出现,随着对象的消失而消失。
            局部变量随着方法的运行而出现,随着方法的弹栈而消失。
    
        区别四:初始化不同。
            成员变量因为在堆内存中,所有的都被默认初始化。
            局部变量没有默认初始化值,必须初始化后才可以使用。
    
    
    【6】什么叫匿名对象?
        (1)匿名对象是对象的简化形式
        (2)匿名对象有两种使用情况
            (*1)当对对象方法仅进行一次调用时。
            (*2)匿名对象可以作为实际参数进行传递。
    
        (*1)匿名对象是为了简化书写,使用场景:当对象对方法进行调用时,而且只调用一次时,可以简化成匿名对象来书写。
            Car c = new Car(); c.run() --->new Car().run();
    
            Car c = new Car();
            c.color = "blue";
            c.run();
            c.run();
            c.run(); 这代表了一个对象多次调用同一个方法。(运行的结果都是color:blue number:0)
    
            是不可以简化成如下书写形式的,因为对象不同!
            new Car().color = "blue";
            new Car().run();
            new Car().run();
            new Car().run();  这代表了三个对象。(运行的结果都是color:null number:0)
    
            所以,当对象需要调用多次成员时,不可以简化成匿名对象调用。
    
        (*2)匿名对象作为实际参数进行传递。
            class Car
            {
                //属性
                String color;
                int number;
    
                    //方法
                void run()
                {
                    System.out.println("color:"+color+"number:"+number);
                }
        
            }
    
            class CarDemo
        {
                public static void main(String[] args)
            {
                /*
                Car c = new Car();
                c.color = "red";
                c.number = 4;
                c.run();
    
                Car c1 = new Car();
                c1.color = "red";
                c1.number = 4;
                c1.run();
                */
    
                //以上代码的复用性较差,只有对象不同,而调用的成员和赋值都相同。
                //可以定义一个功能将重复代码封装。
                /*
                封装功能后,再使用,就简单了。
                */
                Car c = new Car();
                show(c);
    
                Car c1 = new Car();
                show(c1);  //还可以简化为:show(new Car);//把匿名对象作为实际参数进行传递。
    
    
    
            }
        
            //功能的结果是什么呢?没有具体值,所以是void。
            //功能的未知部分是什么呢?对象不明确,可以将其定义为参数。
    
            public static void show(Car cc) //Car cc = c;
            {
                cc.color = "red";
                cc.number = 4;
                cc.run();
             
            }
        }
    
    【7】基本数据和引用数据参数传递过程
        (1)基本数据参数传递:
        class Demo
    {
        public static void main(String[] args)      
        {
            int x = 4;
            show(x);
            System.out.println("x="+x);               打印结果是x=4; 具体可用内存图解进行分析
        }
        public static void /*int*/show(int x)
        {
            x = 5;
            //return x;
        }
    }
    
        (2)引用数据参数传递:
        class Demo
    {
        int x;
        public static void main(String[] args)
        {
            Demo d = new Demo();
            d.x = 5;
            show(d); //show(new Demo());
            System.out.println("x="+d.x);            打印结果是x=6;具体分析可用内存图解进行分析.
        }
        public static void show(Demo d)
        {
            d.x = 6;
        }
    }
    
    
    
    【8】封装:
        表现如下:
        (1)函数就是一个基本的封装体。
        (2)类其实也是一个封装体。
        
        从上面两点知,封装的好处:
        (1)提高了代码的复用性。
        (2)隐藏了实现细节,还要对外提供可以访问的方式。便于调用者的使用,这是核心之一。
        (3)提高了安全性。
    
    【9】面向对象-封装-私有(私有只能修饰成员,不能修饰局部。) (封装:隐藏实现细节,对外提供访问方式。而私有仅仅是封装的一种体现形式)
        总结:
            (1)类中不需要对外提供的内容都私有化,包括属性和方法。
                如下面对方法的私有化
                selectSort(int[] arr)  //选择排序
                {
                    swap();
                }
    
                bubbleSort(int[] arr)  //冒泡排序
                {
                    swap();
                }
    
                private swap(int[] arr,int a,int b)  //这个交换的方法不需要对外提供,就定义为私有
                {
                    code...
                }
        注意:以后再描述事物(创建一个类),属性都私有化,并提供setXxx,getXxx方法对其进行访问。
    
    案例:对人进行描述
          class Person
    {
        //属性
        private int age;  //age就被修饰为了private(私有)。也就是被隐藏了,这就是封装的一种体现
        //行为
        void speak()
        {
            System.out.println("age="+age);
        }
        /*
        年龄已被私有,在这个Person类的外面,错误的值无法赋值,可是正确的值也不能赋值了,这是不行的。
        怎么解决?按照之前所学习的封装的原理,隐藏后,还需要提供访问方式。虽然私有化的Person在类外面
        不能访问了,但是在类里面还可以用类里面的方法进行访问这个私有的Person(一个类中有属性成员和方法成员),
        这就是通过方法的方式对外提供访问的方式。更为重要的是还可以在方法中加入逻辑判断。
    
        注意:对变量的访问操作有两个动作:赋值(设置 set),取值(获取 get)
        所以,对私有的变量访问的方式就是 set变量, get变量
        */
        //定义对age赋值的方法。
        void setAge(int a)
        {
            //加入逻辑判断。
            if(a>0 || a<130)
                age = a;
            else
                //System.out.println("对不起,您的年龄数值"+age+"是非法的!");
                throw new RuntimeException("对不起,您的年龄数值"+age+"是非法的!");
         }
        //定义一个获取age值得方法。
        int getAge()
        {
            return age;
        }
    }
    
    class PersonDemo
    {
        public static void main(String[] args)
        {
            //测试Person.class
            //创建对象。
            Person p = new Person();
    
            /*
            赋值-20是可以的,因为age的属性是int类型,但是不符合现实生活的事实。
            怎么解决?
            不让它访问就可以了。怎么在代码上实现呢?需要用到java中的一个关键字private(私有)
            */
            //p.age = -20; age被私有化了,不能直接访问
            
            //演示的age设置和获取方法的体现。
            p.setAge(20);
            int a = p.getAge();
            System.out.println("a="+a);
            p.speak();
        }
    }
    
    【10-1】面向对象-够造函数-体现
    
    /*
    需求;为了描述事物更准确,发现事物对应的很多对象一创建时,
        就有了一些初始化的数据,(好比人一出生就有姓名和年龄)。
        这在Java中是通过构造函数来完成的。
    
        构造函数有什么用?可以为对象的创建进行初始化。
    
        构造函数怎么在代码中体现呢?
        1.没有返回值类型,因为构造对象,创建完成就结束,不需要结果。void 也不要写,要区别于一般函数。
        2.构造函数的函数名和类名相同。
        3.没有具体的返回值。
    
        按照以上三点,在Person类中体现构造函数。
    */
    
    class Person
    {
        //属性:姓名,年龄
        private String name;
        private int age;
    
        //定义构造函数,对象一创建就具备姓名
        Person(String n)
        {
            //将接受到的值赋值给对象的name
            name = n;
        }
        //行为。
        public void speak()
        {
            System.out.println("name:"+name+",age="+age);
        }
    }
    
    class  PersonDemo2
    {
        public static void main(String[] args) 
        {
            //Person p = new Person();
            //p.speak();
    
            Person p = new person("lisi");//对象创建时,必须会调用对应的构造函数,因为对象要初始化。
            /*
            有了构造函数对对象进行初始化分为两步:(1)在new时先在堆内存中为对象开辟空间,进行默认初始化,
            (2)然后调用构造函数(此时构造函数压栈),再用构造函数对调用它的那个对象进行显示初始化。
            */
            p.speak();
        }
    }
    
    【10-2】面向对象-够造函数-默认构造函数
    
        
    //发现了问题
    /*
    没有学习构造函数时,对象也创建了出来,那么该对象是否有被构造呢?或者说有调用构造函数吗?
    是的,调用了构造函数!
    其实就是调用了类中空参数的默认构造函数。
    class Person
    {
        //属性:姓名,年龄
        private String name;
        private int age;
    
        //默认构造函数
        Person(){}
    
        //行为。
        public void speak()
        {
            System.out.println("name:"+name+",age="+age);
        }
    }
    
    class PersonDemo
    {
        public static void main(String[] agrs)
        {
            Person p = new Person();  //这就已经调用了Person类中默认的构造函数了
                        //只要定义一个类,该类中就有一个空参数的默认构造函数
                        //是Java编译器在完成Java文件的编译时添加到class文件中的
    
                         //注意:如果在类中自定义了构造函数,那么默认的空参数构造函数就不再有了(被覆盖了)
    
                         //原理:没有定义对象的初始化过程,编译器会添加一个默认的初始化过程,如果定义了指定的初始化过程,编译器就不在添加默认的了
    
    }
        
        }    
    
    【10-3】面向对象-够造函数-构造函数的细节
            
    /*
    构造函数的细节:
    1,一个类中可以有多个构造函数。它们是以重载的方式体现的。
    2.构造函数中也是有return语句的,用于结束初始化动作的。
    3.构造函数是否能被private修饰呢? 能,作用就是其他程序无法创建该类的对象,但是在本类里面还是可以创建对象的
                                           如果一个类不想让其他类去创建对象,那就把构造函数私有化。
    class Person
    {
        private Person() {}  //私有化构造函数
    }
    
    main()
    {
        Person p = new Person();  //创建的对象无法初始化。
    }
    */
        
        class Person
    {
        //属性:姓名,年龄
        private String name;
        private int age;
        
        //一初始化,既没有姓名,也没有年龄(某个人失忆了)
        Person()
        {
    
        }
        
        //一初始化,只有姓名,没有年龄
        Person(String n)
        {
            name = n;
        }
    
        //一初始化,既有姓名,又有年龄
        Person(String n,int a)
        {
            name = n;
            age = a;
        }
    
        //行为。
        public void speak()
        {
            System.out.println("name:"+name+",age="+age);
        }
    }
    
    class PersonDemo
    {
        public static void main(String[] args)
        {
            Person p1 = new Person();
            Person p2 = new Person("lisi");
            Person p3 = new Person("wangwu",21);
    
        }
    }
    
    【10-4】面向对象-够造函数-构造函数和一般函数的区别
        明确:一般函数代表的是事物应该具有的一些功能,当需要这些功能的时候,调用就可以了
            ,前提是必须先有对象,而对象的创建必须要进行构造,(不够造,无对象)
    
        1,写法上不一样,构造函数没有返回值类型,构造函数名和类名一样。
        2,运行上有差别,对象一创建就会调用对应的构造函数,一般方法是对象创建后,才会调用所需的一般函数,所以
               对象的创建必须要有构造函数。
    
        问:有了构造函数初始化姓名,那么还需要setName方法吗? 
            需要,因为对象创建后,如果需要对数据进行修改,可以通过set完成。
        class Person
    {
        //属性,姓名
        private String name;
    
        //构造函数
        Person(int n)
        {
            name = n;
        }
    
        //设置姓名的一般函数
        void setName(int n)
        {
            name = n;
        }
    
        //一般方法
        void show()
        {
            System.out.println("name:"+name);
        }
    }
    
    class PersonDemo
    {
        public static void main(String[] agrs)
        {
            Person p = new Person("lisi");
            p.show();  //输出解果为name:lisi
    
            p.setName("wangwu");
            p.show(); //输出结果为name:wangwu   //同一个人通过一般的方法(setName)改了名字。 
        }
    }
        3,构造函数在创建对象时,仅调用一次(初始化动作只做一次,而且先执行),而一般方法可以被对象调用多次
    
    【10-5】面向对象-够造函数-构造函数互相调用(this调用原理图day07-26)
        当构造函数之间进行相互调用时,该如何解决呢?
        
        构造函数是对象初始化时调用的。
        但具体给哪个对象初始化呢?通过this关键字来记录对象的地址,并通过this引用来明确被初始化的对象
    
        在构造函数中调用其他构造函数的格式:this(实参列表),就会调用对应的构造函数
    
            小结:
                this到底代表什么呢?
                this就代表对象,代表哪个对象呢? 哪个对象调用了this所在的函数(每个函数里面都持有一个this引用),this就代表哪个对象。
    
    class Person
    {
        private String name;
        private int age;
        //构造函数,不做任何初始化的动作
        Person()
        {
    
        }
    
        //构造函数初始化姓名
        private Person(String n)
        {
            name = n;
        }
    
        //初始化姓名和年龄,既然上面已经有了初始化姓名的动作,直接调用就可以了
             Person(String n,int a)
            {
                this(n);   //this代表了当前对象!(说法不对,但可以通过这个说法去理解this引用)(这个this就代表了在class PersonDemo中创建的对象Person p = new Person("lisi",20))
                            //只不过在调用private Person(String n)这个构造函数时,还不知道要给哪个对象初始化,因为此时,对象还没有
                            //创建,所以用this代表当前对象(this(n)--->new Person("lisi")这就相当于调用了private Person(String n)
                            //这个构造函数。
                //name = n;
                age = a;
            }
    }
    
    class PersonDemo
    {
        public static void main(String[] args)
        {
            Person p = new person("lisi",20);
        }
    }
    
    【10-6】构造函数的细节
        1.构造函数只能被对象和其它构造函数调用。
        一般函数不能调用构造函数,
        2,调用其它构造函数的语句必须定义在构造函数的第一行。原因:初始化动作要先执行。  
    
    【10-7】this关键字-区分同名变量
    
    /*
    this关键字的另一个用法:
        可以用thiS标识哪个变量是成员变量。这个标识可以省略不写。
        但是,当局部变量和成员变量同名时,必须用this来标识成员变量。
    */
    
    class Person
    {
        private String name;
        private int age;
    
        (**1**)    Person(String name,int age)
            {
                name = name;
                age = age;
                //如果是这种写法,则执行完speak()函数输出的结果是name:null,age=0
                                         //name:null,age=0
                //这是因为,在执行Person p = new Person("lisi",20),这条语句时,
                //(1)首先在堆内存中为新创建的对象开辟一片内存空间,并对其中的成员变量
                //name和age进行默认初始化为:name=null,age=0.
    
                //(2)然后再调用构造函数,此时构造函数压栈,执行语句name=name,age=age
                //时,这时是局部变量的name和局部变量的age赋值给自己,没有对堆内存中的
                //成员变量name和age产生影响
    
                //(3) 构造函数弹栈后,speak()方法又压栈了,执行输出语句时,输出的是成员变量name和
                //age的值,所以输出的是name=null,age= 0,(还是原来默认初始化的值。),如果想输出正确的
                //的值,则要进行如下操作(**2**)
            }
        (**2**)Person(String name,int age)
            {
                this,name = name;
                this.age = age;  //指明是给当前对象进行赋值
            }
    
        public void speak()
        {
            String name = "haha";
            System.out.println("name:"+/*this.*/name+",age="+this.age);
             //如果是这种情况,则打印的结果是name:haha,age=20
                           //name:haha,age=21
                           //所以这个时候要想打印出
                           //name:lisi,age=20 和 name:xiaoming,age=21
                          //则this一定不能省略!System.out.println("name:"+this.name+",age="+this.age);
        }
    /*        //其实在方法之间的调用中也有一个this引用,如下:
        public void method()
        {
            this.speak();  //这个this可以省略不写,因为方法区分还可以有参数列表来区分(就是重载)
                    //而变量名一但重名,就没法区分了,所以当变量名重名时必须要用this关键字
                    //来区分。
        }
    */
    
    /* 小练习,定义功能,判断两个人是否是同龄人?
       //明确结果,boolean 2,明确未知内容,1个,Person类型
        public boolean equalsAge(Person pp)
        {
            /*if(pp.age == this.age) //当函数中使用到了调用该函数的对象时,用this表示这个对象。
                return true;
            else
                return false;*/
            //return (pp.age== this.age)?true:false;
            return pp.age==this.age; //这个写法最好!!!
        }
    */
    
    }
    
    class PersonDemo
    {
        public static void main(String[] args)
        {
            Person p = new Person("lisi",20);
            p.speak();
            Person p1 = new Person("xiaoming"21);
            p1.speak();
        }
    }
    
    
    【11-1】面向对象-static关键字的引入
    class Person
    {
        private String name;
        private int age;
    
        Person(String name,int age)
        {
            this.name = name;
            this.age = age;
        }
    
        public void speak()
        {
            System.out.println("name:"+this.name+",age="+this.age);
    
        }
    
        //定义一个睡觉功能
        public void sleep()
        {
            System.out.println("睡觉zzzZZZ");
        }
    }
    
    class PersonDemo
    {
        public static void main(String[] agrs)
        {
            Person p = new Person("lisi",20);
            //p.speak();
            p.sleep();
            /*
            这个程序运行完后,输出的是:睡觉zzzZZZ, 而没有用到已经在
            堆内存中创建的对象实例。
    
            创建对象就是为了产生实例,并进行数据的封装,而调用功能时,
            却没有用到这些对象中封装的数据,该对象的创建有意义吗?
            
            如果创建了多个对象,这多个对象都没有用到堆内存中的对象实例,
            那么此时虽然可以编译运行,但会出现堆内存空间浪费的问题。
            
            此时,不建议创建对象,那么该怎么调用呢?java中的解决方案就是使用static关键字,这是一个成员修饰符。
            被静态static修饰的方法除了可以被对象调用外,还可以被类名调用
            
            */
        }
    }
    
    【11-2】面向对象-static关键字修饰函数
    class Person
    {
        private String name;
        private int age;
    
        Person(String name,int age)
        {
            this.name = name;
            this.age = age;
        }
    
        public void speak()
        {
            System.out.println("name:"+this.name+",age="+this.age);
    
        }
    
        //定义一个睡觉功能
        public static void sleep()
        
            System.out.println("睡觉zzzZZZ");
        }
    }
    
    class PersonDemo
    {
        public static void main(String[] agrs)
        {
            Person.sleep();
            //Person p = new Person("lisi",20);
            //p.speak();
            //p.sleep();
            /*
            这个程序运行完后,输出的是:睡觉zzzZZZ, 而没有用到已经在
            堆内存中创建的对象实例。
    
            创建对象就是为了产生实例,并进行数据的封装,而调用功能时,
            却没有用到这些对象中封装的数据,该对象的创建有意义吗?
            
            如果创建了多个对象,这多个对象都没有用到堆内存中的对象实例,
            那么此时虽然可以编译运行,但会出现堆内存空间浪费的问题。
            
            此时,不建议创建对象,那么该怎么调用呢?java中的解决方案就是使用static关键字,这是一个成员修饰符。
            被静态static修饰的方法除了可以被对象调用外,还可以被类名调用
            
            那什么时候需要将方法定义成静态的呢?
            定义功能时,如果功能不需要访问类中定义的成员变量时,该功能就定义成静态的。
            如本程序中的功能sleep()这个功能就没有用到成员变量(非静态),所以可以定义成静态的
            */
        }
    }
    
    【11-3】面向对象-static关键字使用细节
        
        /*
        1,静态方法不能访问非静态的成员。
        但是非静态是可以访问静态成员的。
         说明:静态的弊端在于访问出现局限性,(静态只能访问静态)好处是可以直接由类名调用。
        
        2,静态方法中不允许出现this,super关键字。
    
        为什么不能出现this和super呢?
        1,静态是随着类的加载就加载了。也是随着类的消失而消失了。
        2,静态优先于对象存在,被对象共享。
        3,因为静态先存在于内存中无法访问后来的对象中的数据,所以静态无法访问非静态。
          而且内部无法书写this,因为这时对象有可能不存在,this没有任何指向。
        */11-4】面向对象-static关键字-main函数是静态的
        
    /*静态的主函数
     public :权限最大。
     static:不需要对象,直接用给定的类名就可以访问该函数了。
     void   :不需要返回值。
     main   :函数名,该名称是固定的,不能改,一旦改动,就成了自己定义的函数了
     (String[] args) :主函数的参数列表,字符串数组类型的参数。
     args     :arguments:参数。该名称就是一个变量名。
    
     class MainDemo
     {
         public static void main(String[] args)
         {
             System.out.println(args); //[Ljava.lang.String;@659e0bfd(@的左边代表对象的类型,@的右边代表对象的哈希值) //这个结果说明jvm传递了一个数组类型的实体。
             System.out.println(args.length);  //0,得出结论 jvm传递的是new String[0]
            //想要往主函数里面传参数,可以在控制台写 【java MainDemo 传递的参数列表(用空格分开)】 打印的时候可以用一个for循环
            // 把刚才传递的参数都可以打印出来。
         }
     }
    */
    
    class MainDemo
    {
        public static void main(String[] args)
        {
            /*MainDemo.*/show();
        }
    
        public static void show() {} //如果用主函数直接调用方法,必须加静态
                                    //如果这个show方法不是静态的呢?
                                    //该怎样让主函数来访问呢?
                                    //这时可以用对象的方法来访问
        {
            System.out.println("show run");
        }
    }
    
    
    //如果show不是静态的方法,用对象的方法来让主函数访问
    class MainDemo
    {
        public static void main(String[] args)
        {
            ///*MainDemo.*/show();
            new MainDemo().show();
        }
    
        public  void show()  //如果用主函数直接调用方法,必须加静态
                                    //如果这个show方法不是静态的呢?
                                    //该怎样让主函数来访问呢?
                                    //这时可以用对象的方法来访问
        {
            System.out.println("show run");
        }
    }
    
    【11-5】面向对象-static关键字-静态变量
        什么时候定义静态变量呢?
        当该成员变量的值,每一个对象都一致时,就对该成员变量进行静态修饰。
    
        静态变量和成员变量的区别:
        1,所属的范围不同,
        静态变量所属于类,成员变量所属于对象。
        静态变量也称为:类变量;成员变量也称为实例变量。
    
        2,调用不同:
        静态变量可以被对象和类调用(一般用类名调用)
        成员变量只能被对象调用。
    
        3,加载时期不同。
        静态变量随着类的加载而加载,
        成员变量随着对象的加载而加载。
    
        4,内存存储区不同。
        静态变量存储在方法区中,
        成员变量存储在堆内存中。
    
        class Circle
    {
        private double radius;  //圆半径
        private static double pi = 3.1415926;//每一个圆对象都存储一份,有点浪费内存空间,实现对象的共享,加入静态关键字修饰
        Circle(double radius)
        {
            this.radius = radius;
        }
        //获取圆的面积。
        double getArea()
        {
            return radius*radius*/*Circle.*/pi;
        }
    }
    
    class CircleDemo
    {
        public static void main(String[] args)
        {
            
        }
    }
    
    【11-6】面向对象-static关键字-静态加载的内存图解(***day08-静态-单例-继承-36)
    
    【11-7】面向对象-static关键字-静态代码块
    
    /*
    需求:类一加载,需要做一些动作,不一定需要对象。
    学习目标:必须了解加载的顺序。
    
    静态代码块:
        特点:随着类的加载而执行。仅执行一次,
        作用:给类进行初始化。把这个类先注册到某一个应用程序上时会用到。
              和对象没关系,要优于对象先做。
    
    */
    
    class Demo
    {
        static int x = 9;  //静态变量有两次初始化,一次是默认初始化,一次是显示初始化
        
        static //静态代码块,在静态变量显示初始化以后再执行,因为静态代码块有可能会用到这个变量。
        {
            System.out.println("类加载就执行的部分。");
        }
        static void show()
        {
            System.out.println("show run");
        }
    }
    
    class StaticCodeDemo
    {
        public static void main(String[] args)
        {
            Demo.show();  //输出结果是:类加载就执行的部分。
                        //  show run
        }
    }
    
    
    
    【11-8】面向对象-static关键字-构造代码块
    
        class Demo
    {
        //构造代码块,只要创建对象就会被调用,给所有对象初始化,而
        //构造函数只给对应的对象针对的进行初始化。
    
        //这里面可以定义不同构造函数的共性代码。
    
        {
            int x = 4; //构造代码块会在成员变量显示初始化完成后再执行。
            System.out.println("code run");
            System.out.println("----->haha");
        }
    
        Demo()
        {
            System.out.println("Demo run");
            //System.out.println("------>haha"); //两个构造函数有相同的代码,可以写在构造代码块里去
    
        }
    
        Demo(int x)
        {
            System.out.println("Demo run...."+x);
            //System.out.println("------>haha");//两个构造函数有相同的代码,可以写在构造代码块里去
    
        }
    }
    
    class ConstructorCodeDemo
    {
        public static void main(String[] args)
        {
            new Demo();  //这条语句先调用Demo类中的构造代码块
                         //再调用自定义的构造函数。
            new Demo(5);
        }
    }
    
                    //输出的结果会是: code run
                      //------>haha
                      //Demo run
                      //code run
                      //------>haha
                      //Demo run....5
    11-9】面向对象-static关键字-局部代码块
    
        class Demo
    {
        //构造代码块,只要创建对象就会被调用,给所有对象初始化,而
        //构造函数只给对应的对象针对的进行初始化。
    
        //这里面可以定义不同构造函数的共性代码。
        {
            int x = 8;
            System.out.println("code run..."+x);
            //System.out.println("----->haha");
        }
    
        Demo()
        {
            System.out.println("Demo run");
            //System.out.println("------>haha"); //两个构造函数有相同的代码,可以写在构造代码块里去
    
                       //输出的结果会是:code run...8
                             //Demo run
        }
    
        Demo(int x)
        {
            System.out.println("Demo run...."+x);
            //System.out.println("------>haha");
            
            //输出的结果会是:code run...8
                      //Demo run....5
        
        }
    }
    
    class ConstructorCodeDemo
    {
        public static void main(String[] args)
        {
            new Demo();  //这条语句先调用Demo类中的构造代码块
                         //再调用自定义的构造函数。
            new Demo(5);
    
            //int x = 6; 如果把x定义在这里,此时(**1**)和(**2**)处都可以访问到x这个变量
    
            {//局部代码块。 作用就是可以控制局部变量的生命周期
                int x =6; //但是把x定义在这里,只有(**1**)处能访问,(**2**)处不能访问
                (**1**) System.out.pritnln("局部代码块..."+x);
    
            }
            (**2**) System.out.println("over..."+x);
        }
    }
    
    【12】面向对象-对象的创建过程(详解图见F:\javaSE_code\详解图\对象在内存中创建的详解图)
    
        class Demo
    {
        static int x = 1;
        int y = 1;
    
        static  //静态代码块
        {
            System.out.println("static code...x="+x);
        }
        //构造代码块
        {
            System.out.println("cons code ...y="+y);
        }
    
        //构造函数
        Demo()
        {
            /*
            构造函数内的隐式部分:
            1,super();  //访问父类中的构造函数。
            2,成员变量的显示初始化。
            3,构造代码块初始化(因为构造代码块有可能用到成员变量,所以要等成员变量显示初始化完后,再调用。)
            */
            System.out.println("cons function ...y="+x);
        }
    }
    
    class CreateObjectTest
    {
        public static void main(String[] args)
        {
            /*
            1,加载Demo.class文件进方法区,并进行空间分配。
            2,如果有静态变量,先默认初始化,再显示初始化。
            3,如果有静态代码块,要执行,仅一次。
            4,通过new在堆内存中开辟空间,并明确首地址。
            5,对对象中的属性进行默认初始化。
            6,调用对应的构造函数进行初始化。
            7,构造函数内部
                7.1,调用父类的构造函数super();
                7.2,成员变量的显示初始化
                7.3,构造代码块初始化,
                7.4,构造函数内容自定义初始化。
            8,对象初始化完毕后,将地址赋值给d引用变量。
            */
            Demo d = new Demo();
        }
    }
    
    【13-1】面向对象-单例模式-应用场景及代码体现
    
        /*
    设计模式,解决某一类问题行之有效的解决方法(思想).
    单例(Singleton)设计模式。
    学习设计模式必须先弄清楚它是解决什么问题的。
    单例是解决什么问题的呢?
    可以保证一个类的对象唯一性。
    
    应用场景:比如多个程序都要使用一个配置文件中的数据,而且要实现数据共享和交换。
              必须要将多个数据封装到一个对象中,而且多个程序操作的是同一个对象,
              那也就是说要保证这个配置文件对象的唯一性。
    
    怎么能保证对象的唯一性呢?
    1,一个类只要提供了构造函数,就可以产生多个对象。
        完全无法保证唯一性。
    既然数量不可控,干脆,不让其他程序建立对象。(就用到了private)
    
    2,不让其他程序创建,对象何在?
        干脆,自己在本类中创建一个对象,这样的好处是什么  可控。
    
    3,创建完成后,还要给其他程序提供访问的方式
    
    
    怎么实现这个步骤呢?
    1, 怎么就能不让其他程序创建对象呢?
        直接私有化构造函数,不让其他程序创建的对象初始化,就达到了不让其它类创建对象的目的了。
    
    2,直接在本类中new一个本类的对象。
    
    3,定义一个功能,其他程序可以通过这个功能获取到本类的对象。 
    */
    
    //代码体现
    class Single
    {
        //2,创建一个本类对象
        /*private*/ static Single s = new Single(); //下面的getInstance方法(静态)要想调用这个本类对象,
                                        //这个本类对象必须加静态才能被调用。
                            
        //1,私有化构造函数
        private Single(){}
    
        //3,定义一个方法返回这个对象,
         public static Single getInstance()  //这个方法加静态是为了给其他程序提供
                            //获取本类对象的入口,因为本类的构造函数
                             //已被私有化了,不能通过在其他类中创建本类
                             //的对象,只能通过定义一个功能来实现其它类
                            //来获取本类对象,也就出现了getInstance这个方法
                            //但是在其他程序中要想调用这个getInstance方法来获取
                             //这个类的对象,又必须通过对象或者类名的方式来调用。
                            //现在已经无法再其他程序中创建此类的对象,就不能通过对象
                             //来调用了,就只能通过类名来调用,既然要通过类名来调用
                            //那么此类中的这个getInstace方法必须是静态的,所以就出现的
                            //static 这个关键字。
    
                            //这个方法是其他程序用来获取本类对象的,所以它的权限要足够大。
                            //所以定义成public
        {
            return s;
        }
    }
    
    
    
    class SingleDemo
    {
        public static void main(String[] args)
        {
            //要想获取Single的对象,需要调用getInstance方法,既然无法通过对象调用,
            //那就只能通过类名来调用了。所以getInstance方法要是静态的。
            Single ss = Single.getInstance();
            Single ss2 = Single.getInstance();  //这两个使用的是同一个对象,
        }
    }
    
    
    【13-2】面向对象-单例模式-小问题
    
    class Single
    {
        //2,创建一个本类对象
        private static Single s = new Single(); //下面的getInstance方法(静态)要想调用这个本类对象,
                            //这个本类对象必须加静态才能被调用。
    
                            //既然这个对象不对外提供,那就直接将其私有化
        //1,私有化构造函数
        private Single(){}
    
        //3,定义一个方法返回这个对象,
         public static Single getInstance()  //这个方法加静态是为了给其他程序提供
                                      //获取本类对象的入口,因为本类的构造函数
                                      //已被私有化了,不能通过在其他类中创建本类
                                      //的对象,只能通过定义一个功能来实现其它类
                                      //来获取本类对象,也就出现了getInstance这个方法
                                      //但是在其他程序中要想调用这个getInstance方法来获取
                                      //这个类的对象,又必须通过对象或者类名的方式来调用。
                                      //现在已经无法再其他程序中创建此类的对象,就不能通过对象
                                      //来调用了,就只能通过类名来调用,既然要通过类名来调用
                                      //那么此类中的这个getInstace方法必须是静态的,所以就出现的
                                      //static 这个关键字。
    
                                      //这个方法是其他程序用来获取本类对象的,所以它的权限要足够大。
                                      //所以定义成public
        {
            return s;
        }
    }
    
    
    
    class SingleDemo
    {
        public static void main(String[] args)
        {
            //要想获取Single的对象,需要调用getInstance方法,既然无法通过对象调用,
               //那就只能通过类名来调用了。所以getInstance方法要是静态的。
            Single ss = Single.getInstance();
            Single ss2 = Single.getInstance();  //这两个使用的是同一个对象,
    
            //问题来了:
            //既然new出来的对象也是静态的,直接用类名调用不也行吗? 如下:
    
            Single ss = Single.s;
            Single ss2 = Singel.s;  //这两个调用的也是同一个对象。
    
            //但上面这种调用方式不好,(可以通过 对属性成员进行private的思考方式 来分析,当时是把属性成员定义为private类型,
            //然后再提供对外访问属性的方法setxxxXXX  getxxxXXX,是为了实现对属性成员安全性的可控,在这里也可以用相同的方式思考
            //如果代码写成如下方式就可以明白了)
    
    /***********************************************************************************
            class Single
    {
        /*public*/static Single s = new Single()
        
        private Single(){}
    
        public static Single getInstance(int x)
        {
            if(x<0)   //如果用户传递的参数不对,就不让其访问对象。保护了对象的安全性。
                return null;
            return s;
        }
    }
    
    class SingleDemo
    {
        public static void main(String[] args)
        {
            Single ss = Single.getInstance();
            Single ss2 = Single.getInstace();
    
            //Single ss = Single.s;//这样做,虽然可以实现调用对象
                                    //和上面的访问方式结果是一样的,
                                    //但是不能保证这个唯一对象的安全性。
    
            //Single ss2 = Single.s
        }
    }
    
    //既然对象不想对外提供,那就把他定义成私有的。此时通过类名也不能直接访问对象s(被private了),只能通过类名访问方法getInstance来获取对象。
    
    **************************************************************************************            
                
        }
    }
    
    
    
    【13-3】面向对象-单例模式-单例模式的另种体现
    
        //饿汉式 单例模式(开发中用的最多的是这个)
    class Single
    {
        //2,创建一个本类对象
        private static Single s = new Single();  //这个类一加载后,这个静态变量就会加载到方法区中的静态代码区中
                            //然后先进行默认值得初始化,为null,紧跟着就要进行显示初始化
                             //这时就意味着这个类(class Single)一加载,堆内存中就创建了对象
                            //当调用getInstance方法时对象已经存在在堆内存中了。
    
        //1,私有化构造函数
        private Single(){}
    
        //3,定义一个方法返回这个对象,
         public static Single getInstance() 
        {
            return s;
        }
    }
    
    
    
    
    
    
    
    //赖汉式单例模式  (面试中用的最多的是这个)
    //单例(单例就是单独的对象)的延迟加载方式
    class Single2
    {
        //2,创建一个本类对象
        private static Single s2 = null;  //这样做的好处及目的是:这个类(class Single)一旦被加载
                        //这个静态变量就会加载到方法区中的静态代码区中,然后进行默认初始化
                        //再进行显示初始化,此时其默认值和显示值是一样的,这时不会再堆内存
                        //产生对象,而是在调用getInstance这个方法时才会在堆内存中产生对象
    
        //1,私有化构造函数
        private Single2(){}
    
        //3,定义一个方法返回这个对象,
         public static Single getInstance()                               
        {
             if(s2==null)
                 s2 = new Single2();
            return s2;
        }
    }
    
    
    
    class SingleDemo
    {
        public static void main(String[] args)
        {
            //要想获取Single的对象,需要调用getInstance方法,既然无法通过对象调用,
            //那就只能通过类名来调用了。所以getInstance方法要是静态的。
            Single ss = Single.getInstance();
            Single ss2 = Single.getInstance();  //这两个使用的是同一个对象,
        }
    }
    
    【13-4】面向对象-单例模式-单例模式的应用
    
        
    class SuperMan
    {
        private String name;
    
        private static SuperMan man = new SuperMan("克拉克");
    
        private SuperMan(String name)
        {
            this.name = name;
        }
    
        public static SuperMan getInstance()
        {
            return man;
        }
    
        public void setName(String name)
        {
            this.name = name;
        }
    
        public String getName()
        {
            return this.name;
        }
    
        public void fly()
        {
            System.out.println(this.name+"...fly");
        }
    }
    
    class SingleTest
    {
        public static void main(String[] args)
        {
            //不能new很多SuperMna,因为超人是唯一的,用单例模式解决
    //        SuperMan man = new SuperMan("克拉克");
            //SuperMan man = new SuperMan("克拉克");
            //SuperMan man = new SuperMan("克拉克");
            //SuperMan man = new SuperMan("克拉克");
            //SuperMan man = new SuperMan("克拉克");
            //SuperMan man = new SuperMan("克拉克");
    
            SuperMan man1 = SuperMan.getInstance();
            SuperMan man2 = SuperMan.getInstance();
    
            man1.setName("英雄");
            man2.fly();
            //输出结果会是 英雄...fly,因为man1和man2指向了同一个对象。
        }
    }
  • 相关阅读:
    Navicat连接MySQL数据库的一些问题与解决方案
    从select机制谈到epoll机制
    关于VS2017提示I/O文件操作函数需要加上_s的解决办法
    LeetCode初级算法(树篇)
    LeetCode初级算法(动态规划+设计问题篇)
    LeetCode初级算法(其他篇)
    Leetcode初级算法(排序和搜索+数学篇)
    Leetcode初级算法(链表篇)
    Leetcode初级算法(字符串篇)
    机器学习之k-近邻算法
  • 原文地址:https://www.cnblogs.com/sun-/p/5208780.html
Copyright © 2020-2023  润新知