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

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

    学而不思则罔 思而不学则殆
  • 相关阅读:
    手把手带你画一个 时尚仪表盘 Android 自定义View
    新手自定义view练习实例之(二) 波浪view
    新手自定义view练习实例之(一) 泡泡弹窗
    增加辅助的数据库组件
    解决Plugin is too old,please update to a more recent version,or set ANDROID_DAILY_OVERRIDE..
    Android 自定义View -- 简约的折线图
    android 开源图表库MPChart最简单使用方法示例教程Demo--折线图 柱状图
    改善database schema
    题解报告:hdu 2057 A + B Again
    hdu 2087 剪花布条(KMP入门)
  • 原文地址:https://www.cnblogs.com/liu-wang/p/8182024.html
Copyright © 2011-2022 走看看