zoukankan      html  css  js  c++  java
  • java-静态-单例-继承

    概要图

    一.静态

    1.1 静态方法

    创建对象就是为了产生实例,并进行数据的封装。
    而调用功能时,确没有用到这些对象中封装的数据。
    该对象的创建有意义吗?虽然可以编译并运行,但是在堆内存中空间较为浪费

    不建议创建对象。那该怎么调用呢?java中的解决方案就是 使用 static关键字,这是一个成员修饰符。
    被静态static修饰的方法除了可以被对象调用外,还可以被类名调用。
    静态看上去很美,是不是所有的方法都静态呢?不行

    那么什么时候需要将方法定义成静态的呢?
    定义功能时,如果功能不需要访问类中定义的成员变量(非静态)时,该功能就需要静态修饰

    1.2 静态方法使用注意事项:

    1,静态方法不能访问非静态的成员。
    但是非静态可以访问静态成员的。
    说明:静态的弊端在于访问出现局限性。好处是可以直接被类名调用。

    2,静态方法中不允许出现this,super关键字。


    为什么不行呢?

    1.3 原理揭秘:

    1,静态是随着类的加载就加载了。也是随着类的消失而消失了。
    2,静态优先于对象存在,被对象共享。
    3,因为静态先存在于内存中无法访问后来的对象的中的数据,所以静态无法访问非静态。
    而且内部无法书写this。因为这时对象有可能不存在,this没有任何指向。

    1.4 静态的主函数:

    public static void main(String[] args)

    public : 权限最大。
    static :不需要对象。直接用给定的类名就可以访问该函数了。
    void : 不需要返回值。
    main : 函数名,该名称是固定的。
    (String[] args) : 主函数的参数列表:字符串属性类型的参数。
    args : arguments :参数。该名称就是一个变量名。

    class MainDemo 
    {
    	public static void main(String[] args) 
    	{
    		System.out.println(args);//[Ljava.lang.String;@1afae45//根据这个结果,说明jvm传递了一个字符串类型的数组实体。
    		System.out.println(args.length);//0,得出结论 jvm传递的是 new String[0];
     
    		for (int i = 0; i<args.length ;i++ )
    		{
    			System.out.println(args[i]);
    		}
    	}
    
    	void show()
    	{
    		System.out.println("show run");
    	}
    }
    

    1.5静态变量

    什么时候定义静态变量呢?
    当该成员变量的值,每一个对象都一致时,就对该成员变量进行静态修饰。

    静态变量和成员变量的区别:
    1,所属范围不同。
    静态变量所属于,成员变量所属对象
    静态变量也称为:类变量;成员变量也称为实例变量

    2,调用不同。
    静态变量可以被对象和类调用(一般都用类名调用)
    成员变量只能被对象调用。

    3,加载时期不同。
    静态变量随着的加载而加载。
    成员变量随着对象的加载而加载。

    4,内存存储区域不同。
    静态变量存储在方法区中。
    成员变量存储在堆内存中。

    class Circle
    {
    	private double radius;//圆的半径。
    	private static double pi = 3.14;//每一个圆对象中都存储一份,有点浪费内存空间。实现对象的共享。加入静态关键字修饰。
    	Circle(double radius)
    	{
    		this.radius = radius;
    	}
    	//获取圆的面积。
    	double getArea()
    	{
    		return radius*radius*pi;
    	}
    	static void show()
    	{
    		System.out.println("circle show run.."+pi);
    	}
    }
    class CircleDemo 
    {
    	public static void main(String[] args) 
    	{
    		Circle c = new Circle(3);
    		
    	}
    }
    

    1.6 静态加载的内存图解 

    注意:这个过程对应上面代码

    1 运行一个类 这个类要加载 先在方法区开空间 加载的是字节码文件 也就是.class文件.这里的类是.cirleDemo.classs
    2 在方法区中会开一个专门用来存储静态的static code. ps:main在circleDemo类中.******
    3 从main方法开始入口,把main方法调入到中,
    4 加载.class 文件到方法区 这里的是circle.class
    5 在加载cirle.class时,要把里面的static修饰的成员加载到static code中去.
    6 加载完后 new开空间到里面. radius=0(默认),0x44 构造函数进栈.对成员变量初始化后构造函数弹栈
    7 main方法中 c=0x44 getArea()进栈.

    内存总体分为了4个部分

    包括 stack segmentheap segmentcode segmentdata segment


    其中我们程序中用关键字new出来的东西都是存放在heap segment

    程序中的局部变量存放在stack segment,这些局部变量是在具体方法执行结束之后,系统自动释放内存资源(而heap segment中的资源需要java垃圾回收机制来处理)。

    程序中的方法,是内存中的code segment中的,而且是多个对象 共享一个代码空间区域。

    static静态变量,需要放在内存中的data segment中。

     1.7 静态代码块和局部代码块

    1 静态代码块

    需求:类一加载,需要做一些动作。不一定需要对象。
    学习目标:必须了解加载的顺序。
    静态代码块:
    特点:随着类的加载而执行,仅执行一次
    作用:给类进行初始化。

    class Demo
    {
    	static int x = 9;//静态变量有两次初始化。 一次默认初始化一次显示初始化。
    	static //静态代码块。在静态变量显示初始化以后在执行。
    	{
    		System.out.println("类加载就执行的部..."+x);
    	}
    	static void show()
    	{
    		System.out.println("show run");
    	}
    }	
    
    class StaticCodeDemo 
    {
    	public static void main(String[] args) 
    	{
    		Demo.show();
    		Demo.show();
    	}
    }
    

    2  局部代码块(构造代码块)

    /*
    构造代码块:用于给所有的对象初始化。很少用并很少见。
    
    */
    
    class Demo
    {
    	int x = 4;//成员变量 1,默认初始化,2,显示初始化。
    	{// 构造代码块只要创建对象就会被调用。给所有对象初始化,构造函数只给对应的对象针对性的初始化。
    		//这里面可以定义不同构造函数的共性代码。
    		System.out.println("code run..."+x);     1
    //		System.out.println("----->hahah");
    	}
    
    	Demo()
    	{
    		System.out.println("demo run");
    	}
    	Demo(int x)
    	{
    		System.out.println("demo run...."+x);
    //		System.out.println("----->hahah");
    	}
    
    
    }
    
    class ConstructorCodeDemo 
    {
    	public static void main(String[] args) 
    	{
    		new Demo();
    		new Demo(5);
    
    
    		{//局部代码块,作用就可以控制局部变量的生命周期。       2
    			int x = 5;
    			System.out.println(" 局部代码块..."+x);
    		}
    
    		System.out.println(" over...");
    	}
    }

    二.单例

    2.1 对象的初始化过程@

    注意:这部分和上面的静态加载内存图解类似

    下面讲解的更加详细

    //对象的初始化过程。
    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()
    {
    System.out.println("cons function ...y="+y);
    }
    }
    
    
    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();
    }
    }
    

    2.2 单例@@

    设计模式:解决某一类问题行之有效的解决办法(思想)。
    单例(Singleton)设计模式:
    学习设计模式必须先弄清楚它是解决什么问题的@@@
    单例是解决什么问题的呢?
    可以保证一个类的对象唯一性。

    场景:比如多个程序都要使用一个配置文件中的数据,而且要实现数据共享和交换。
    必须要将多个数据封装到一个对象中。而且多个程序操作的是同一个对象
    那也就是说必须保证这个配置文件对象的唯一性。

    怎么能保证对象的唯一性呢?
    1,一个类只要提供了构造函数,就可以产生多个对象。
    完全无法保证唯一。
    既然数量不可控,干脆,不让其他程序建立对象。

    2,不让其他程序创建,对象何在?
    干脆,自己在本类中创建一个对象,这样好处是什么,可控。

    3,创建完成后,是不是要给其他程序提供访问的方式。

    怎么实现这个步骤呢?
    1,怎么就能不其他程序创建对象呢?
    直接私有化构造函数,不让其他程序创建的对象初始化。

    2,直接在本类中new一个本类对象。

    3,定义一个功能,其他程序可以通过这个功能获取到本类的对象。

    哦耶。 

    代码体现。
    //饿汉式

    class Single
    {
    //2,创建一个本类对象。
    private static /*final*/ Single s = new Single();
    
    //1,私有化构造函数。
    private Single(){}
    
    //3,定义一个方法返回这个对象。
    public static Single getInstance()
    {
    return s;
    }
    }  

    //懒汉式
    //单例的延迟加载方式。面试最多的是懒汉式。

    class Single2
    {
    private static Single2 s2 = null;
    
    private Single2(){}
    
    public static Single2 getInstance()
    {
    if(s2==null)
    s2 = new Single2();
    return s2;
    }
    }

    注意:上面的两种方式的区别在于因为是静态的,一个是在类加载就生成对象,另一个是在调用方法时才产和对象

    //练习:将两种方式的内存图画出来。

    class SingleDemo
    {
    public static void main(String[] args) 
    {
    //要想获取Single的对象。调用getInstance方法。既然无法通过对象调用,只能用类名调用,所以这个方法必须是static。
    Single ss = Single.getInstance();
    Single ss2 = Single.getInstance();
    
    
    //	Single ss = Single.s;//这种方式是可以实现,加入访问来获取就是为了对对象可控。
    //	Single ss2 = Single.s;
    }
    }

     三 , 继承

    3.1 继承

    /*
    //描述学生。
    class Student 
    {
    //属性。
    String name;
    int age;
    
    //行为。
    void study()
    {
    System.out.println("good good study");
    }
    }
    
    //描述工人。
    class Worker
    {
    //属性。
    String name;
    int age;
    
    //行为
    void work()
    {
    System.out.println("hard work");
    }
    }
    */
    
    /*

    了提高复用,只建立一份代码。
    一个类只要和另一个类产生关系就可以了
    关系:继承。
    发现了获取到所需内容的同时也获取到不该具备的内容。
    为什么?
    发现原来这个两个类之间根本就不存在继承关系。

    只要通过关键字 extends(继承) 就哦了。
    
    */
    
    class Person
    {
    String name;
    int age;
    
    }
    
    class Student extends Person//学生继承了Person 学生就是子类 Person就是父类(基类,超类)
    {
    void study()
    {
    System.out.println("good good study");
    }
    }
    class Worker extends Person
    {
    void work()
    {
    System.out.println("hard work");
    }
    }
    /*

    怎么解决呢?
    找到学生和工人的共性类型。将需要提供复用的代码进行抽取。
    定义到一个共性类型的类中。
    Person name age。

    怎么在代码体现中让学生和Person产生关系呢?

    面向对象 另一个特征:继承。
    好处:提高了代码的复用性。让类与类产生了关系,给另一个特征 多态 提供了前提。

    什么时候定义继承?
    必须保证类与类之间有所属(is a)关系。 xxx是zzz中的一种。
    苹果是水果中一种。狗是犬科中一种。


    在Java中继承的体现:
    Java允许单继承。不直接支持多继承,将多继承进行其他方式的体现。
    单继承:一个子类只能有一个父类。
    多继承:一个子类可以有多个父类。


    看上起,多继承很厉害!为什么。

    class Fu1
    {
    void show1()
    {}
    }
    class Fu2
    {
    void show2()
    {}
    }
    //多继承。
    class Zi extends Fu1,Fu2
    {
    
    }
    
    Zi z = new Zi();
    z.show1();
    z.show2();
    //问题随之而来
    万一多个父类具备了相同的功能呢?
    class Fu1
    {
    void show()
    {
    sop("fu1 show run");
    }
    }
    class Fu2
    {
    void show()
    {    
    sop("fu2 show run");
    }
    }
    //多继承。
    class Zi extends Fu1,Fu2
    {
    
    }
    
    Zi z = new Zi();

    z.show();//调用就会产生不确定性。所以java保留的多继承的好处,改良它的弊端。用多实现来体现,即将学到。

    java还支持多重继承。

    class A
    {}
    class B extends A
    {}
    class C extends B
    {}
    
    形成继承体系。
    学习继承体系时,应该参阅顶层的类中的内容。
    了解这个体系的基本功能。
    
    使用这个体系功能,需要创建最子类的对象。
    
    看顶层,建底层。
    
    */
    
    
    class ExtendsDemo 
    {
    public static void main(String[] args) 
    {
    Student stu = new Student();
    stu.name = "xiaoqiang";
    stu.age = 12;
    stu.study();
    
    }
    }


    作者:8亩田
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接.

    本文如对您有帮助,还请多帮 【推荐】 下此文。
    如果喜欢我的文章,请关注我的公众号
    如果有疑问,请下面留言

    学而不思则罔 思而不学则殆
  • 相关阅读:
    ZeptoLab Code Rush 2015
    UVa 10048 Audiophobia【Floyd】
    POJ 1847 Tram【Floyd】
    UVa 247 Calling Circles【传递闭包】
    UVa 1395 Slim Span【最小生成树】
    HDU 4006 The kth great number【优先队列】
    UVa 674 Coin Change【记忆化搜索】
    UVa 10285 Longest Run on a Snowboard【记忆化搜索】
    【NOIP2016提高A组模拟9.28】求导
    【NOIP2012模拟10.9】电费结算
  • 原文地址:https://www.cnblogs.com/liu-wang/p/8182024.html
Copyright © 2011-2022 走看看