黑马程序员 笔记(六)——面向对象(static关键字、静态、main函数、、帮助文档、对象的调用和初始化、单例)

------- android培训java培训、期待与您交流! ----------

static关键字以及静态

  1. 用途:是一个修饰符,只能用于修饰成员(成员变量和成员函数)。不能修饰局部变量。
  2. 被修饰后的成员具备一下特点:
    1. 随着类的加载而加载,随着类的消失而消失。
    2. 优先于对象存在。
    3. 被所有对象所共享。(任意一个对象更改了静态数据,那么其他对象使用数据时使用的就是更改后的数据。)
    4. 不仅可以被对象调用,并且可以直接被类名调用。格式:类名.静态成员
    5. 被static修饰的成员不在堆内存里,而是在方法区。
  3. 静态使用的注意事项:
    1. 静态方法只能访问静态成员,非静态方法既能访问非静态又可以访问非静态。
    2. 静态中不能使用this和super等关键字。因为静态是随类的加载而加载,优先于对象的存在。而this和super指的是对象。
    3. 主函数是静态的。
  4. 实例变量和类变量(被static修饰的变量)的区别
    1. 存放的位置
      • 类变量:随着类的加载而加载,存在于方法区中。
      • 实例变量:随着对象的建立而建立,存在于堆内存中。
    2. 生命周期:
      1. 类变量:生命周期最长,随着类的消失而消失。
      2. 实例变量:随着对象的消失而消失。
  5. 静态的利弊:
    • 好处:对对象的共享数据进行单独空间存贮,节省空间。
    • 弊端:
      1. 生命周期过长
      2. 访问出现局限性,只能访问静态成员。
  6. 注意:静态不能用于修饰局部变量,因为局部变量只在定义他的那个方法或者代码块中有效。但是如果被静态修饰,则只有类消失时,该变量才会消失。
  7. 什么时候定义静态变量(类变量)?
    • 当对象中出现共享数据时,该数据被静态所修饰。如所有的中国人的国籍。
  8. 什么时候定义静态函数呢?
    • 当功能内部没有访问到非静态数据(对象的特有数据),那么该功能可以定成静态的。
  9. 静态方法的应用:
    • 每一个应用程序中都有共性的功能,可以把这个功能进行抽取,独立封装形成一个只含有静态方法的类以便复用。(但是将方法静态后,该类还是可以被其他程序建立对象,为了更加严谨,可以强制让该类不能建立对象。方法是私有化构造函数
    • 代码诠释(将前面的操作数组的函数可以改写成以下代码,以提高代码的复用性)
      class ArrayTool
      {
      //	私有空参数构造函数,防止建立对象
      	private ArrayTool(){}
      
      //	给int数组进行选择排序。
      	public static int[] selectSort(int[] arr)
      	{
      		for (int x=0; x<arr.length-1 ; x++ )
      		{
      			for(int y=x+1; y<arr.length; y++)
      			{
      				if(arr[x]>arr[y])
      				{
      					swap(arr,x,y);
      				}
      			}
      		}
      		return arr;
      	}
      
      	private  static void swap(int[] arr,int a,int b)
      	{
      		int temp = arr[a];
      		arr[a] = arr[b];
      		arr[b] = temp;
      	}
      //	用于打印数组中的元素。打印形式是:[elemet1, element2, ...]
      	public static void printArray(int[] arr)
      	{
      		System.out.print("[");
      		for(int x=0; x<arr.length; x++)
      		{
      			if(x!=arr.length-1)
      				System.out.print(arr[x]+", ");
      			else
      				System.out.println(arr[x]+"]");
      		}
      	}
      }
      class Arr
      {
      	public static void main(String[] args)
      	{
      		int[] a = {1,4,66,5,76,8};
      
      		ArrayTool.printArray(a);//打印原数组
      
      		ArrayTool.printArray(ArrayTool.selectSort(a));//打印排序过后的数组
      	}
      }
      
      
      
      
      
      
      
      
      • 代码分析:
        • 将操作数组的工具类独立封装成一个类,因为其中的方法没有操作任何该类的特有数据,并且为了能方便调用,因此用静态修饰其中的函数。当调用的时候,只需通过类名调用就可以了。

main函数

  1. 主函数的含义
    • 是一个特殊的函数,作为程序的入口,可以被jvm调用。
  2. 主函数定义详解:jvm的格式是固定的,只有这样才能被jvm识别。
    • public:代表着该函数访问权限是最大的。
    • static:代表主函数随着类的加载就已经存在了。
    • void:主函数没有具体的返回值。
    • main:不是关键字,但是是一个特殊的单词,可以被jvm识别。
    • (String[] args):函数的参数,参数的类型是一个数组,该数组中的元素是字符串,即字符串类型的数组。
    • jvm在调用主函数时,传入的是new String[0]
  3. 主函数传值的例子:
    class MainDemo 
    {
    	public static void main(String[] args)//new String[]
    	{
    		System.out.println(args[0]);
    		System.out.println(args[1]);
    	}
    }

    Dos命令行中执行以下命令:
    • 在这个程序中,在执行的时候往args数组中传了三个字符串“你好”“我好”“大家好”,在程序中只让打印出前面两个,所以打印出了“你好”“我好”。

帮助文档

  1. 需求:当开发的工具编译后生成一个工具包,把这个包发给给别人使用,但是使用者又不知道如何使用,此时便需要制作程序说明书。
  2. 制作工具:JAVA的说明书通过文档注释来完成,通过javadoc命令来完成。
  3. 制作帮助文档的前提
    1. 该类必须有足够大的权限即被public修饰。
    2. 只有被public或者protected修饰的才能被javadoc提取。
    3. 默认的空参数构造函数和类的权限一样,如果类被public修饰,那么默认的构造函数也被public修饰。如果类没有被public修饰,则默认的构造函数也没有被public修饰。
  4. 制作格式以及常用的命令
    /**
    对此工具类的说明,即提供了什么功能
    @author 开发者姓名
    @version 版本
    @param 参数
    @return 返回什么
    */

  5. javadoc命令的使用:
    • javadoc -d 文件夹,当没注明路径时即在当前目录下-author-version(这两个参数及说明是否显示版本和作者)源文件名.java
  6. 代码诠释:
    /**
    这是一个可以对数组进行操作的工具类,该类中提供了,获取最值,排序等功能。
    @author 传智播客学员
    @version V1.1
    
    */
    
    public class ArrayTool
    {
    	/**
    	空参数构造函数。
    	*/
    	private ArrayTool(){}
    
    	/**
    	获取一个整形数组中的最大值。
    	@param arr 接收一个int类型的数组。
    	@return 会返回一个该数组中最大值。
    	*/
    	public static int getMax(int[] arr)
    	{
    		int max = 0;
    		for(int x=1; x<arr.length; x++)
    		{
    			if(arr[x]>arr[max])
    				max = x;
    		}
    		return arr[max];
    	}
    	
    	/**
    	获取一个整形数组中的最小值。
    	@param arr 接收一个int类型的数组。
    	@return 会返回一个该数组中最小值。
    	*/
    	public static int getMin(int[] arr)
    	{
    		int min = 0;
    		for(int x=1; x<arr.length; x++)
    		{
    			if(arr[x]<arr[min])
    				min = x;
    		}
    		return arr[min];
    	}
    	/**
    	给int数组进行选择排序。
    	@param arr 接收一个int类型的数组。
    	*/
    	public static void selectSort(int[] arr)
    	{
    		for (int x=0; x<arr.length-1 ; x++ )
    		{
    			for(int y=x+1; y<arr.length; y++)
    			{
    				if(arr[x]>arr[y])
    				{
    					swap(arr,x,y);
    				}
    			}
    		}
    	}
    	/**
    	给int数组进行冒泡排序。
    	@param arr 接收一个int类型的数组。
    	*/
    	public static void bubbleSort(int[] arr)
    	{
    		for (int x=0; x<arr.length-1 ; x++ )
    		{
    			for(int y=0; y<arr.length-x-1; y++)
    			{
    				if(arr[y]>arr[y+1])
    				{
    					swap(arr,y,y+1);
    				}
    			}
    		}
    	}
    	/**
    	给数组中元素进行位置的置换。
    	@param arr  接收一个int类型的数组。
    	@param a 要置换的位置 
    	@param b 要置换的位置 
    	*/
    	private  static void swap(int[] arr,int a,int b)
    	{
    		int temp = arr[a];
    		arr[a] = arr[b];
    		arr[b] = temp;
    	}
    	/**
    	用于打印数组中的元素。打印形式是:[elemet1, element2, ...]
    	*/
    	public static void printArray(int[] arr)
    	{
    		System.out.print("[");
    		for(int x=0; x<arr.length; x++)
    		{
    			if(x!=arr.length-1)
    				System.out.print(arr[x]+", ");
    			else
    				System.out.println(arr[x]+"]");
    		}
    	}
    }

静态代码块

  1. 格式:
    static
    {
    	静态代码块中的执行语句。
    }
  2. 特点
    • 随着类的加载而加载,只执行一次。用于给类进行初始化的。
  3. 对象建立的过程:  
    1. 图示:
    2. 代码诠释:
      • class StaticCode
        {
        	int num = 9;//成员变量
        
        	//静态代码块
        	static
        	{
        		System.out.println("e");
        		//this.num = 8;
        		//System.out.println("执行静态代码块儿 num = "+this.num);
        	}
        
        	//构造代码块
        	{
        		num = 7;
        		System.out.println("执行构造代码块 num = "+num);
        	}
        
        	//有一个整型变量的构造函数
        	StaticCode(int x)
        	{
        		this.num = x;
        		System.out.println("执行构造函数 num = "+num);
        	}
        }
        
        class StaticCodeDemo 
        {
        	//主函数
        	public static void main(String[] args) 
        	{
        		new StaticCode(4); 
        	}
        
        	//静态代码块
        	static
        	{
        		System.out.println("a");
        	}
        }
        /*
        执行结果
        ============================
        a
        e
        执行构造代码块 num = 7
        执行构造函数 num = 4
        
        ============================
        */主函数的类先
        代码分析:
        • 首先是主函数所在类加载被加载,类一被加载静态代码块执行,所以打印出a,然后是主函数开始执行。创建一个StaticCode的对象,所以StaticCode类被加载,类被加载后执行静态代码块,所以又打印出e,然后是执行构造代码块将7赋值给num,对属性进行初始化,所以接着打印出第三句。最后执行构造函数对对象进行赋值。所以最终num的值是4.
  4. 对象的调用过程:

单例设计模式

  1. 设计模式:解决某一类问题最行之有效的方法。
  2. 单例设计模式:解决一个类在内存中只有一个对象。
  3. 该模式的思想:
    1. 为了避免其他程序过多的建立该类对象,先禁止其他程序建立该类对象。
    2. 为了让其他程序可以访问到该类对象,则在本类中自定义一个对象。
    3. 为了方便其他程序对自定义对象的访问,可以提供一些访问方式。
  4. 代码如何实现:
    1. 防止建立新的对象——将构造函数私有化。
    2. 创建一个对象供其他程序调用——在本类中创建一个本类对象。
      • 此时创建的这个 对象相当于类的一个属性,为了提高安全性则必须将其私有化
    3. 方便其他程序对自定义对象的访问——提供一个方法可以获取该对象。
      • 方法必须有对象或者类调用,然而其他程序不能建立新的对象,所以不能由对象调用。只能由类名调用,因此得把该方法定义成静态的。
  5. 单例设计模式的两种模式:
    • 饿汉式:在类一加载的时候,就初始化一个对象。
      • 代码:
        class Single
        {
        	private Single(){}
        	private static Single s = new Single();
        
        	public static Single getSingle()
        	{
        		return s;
        	}
        }
        
        
        class SingleDemo 
        {
        	public static void main(String[] args) 
        	{
        		Single s1 = Single.getSingle();
        		Single s2 = Single.getSingle();
        
        		if (s1.equals(s2))
        			System.out.println("同一个对象");
        		else
        			System.out.println("不是同一个对象");
        	}
        }

        执行结果是“同一个对象”
    • 懒汉式:类进内存,对象还没有存在,只有调用获取对象方法时,才建立对象。
      • class Single
        {
        	private Single(){}
        	private static Single s = null;
        
        	public static Single getSingle()
        	{	
        		if(s==null)
        			//①
        			s = new Single();
        		return s;
        	}
        }
        
        
        class SingleDemo 
        {
        	public static void main(String[] args) 
        	{
        		Single s1 = Single.getSingle();
        		Single s2 = Single.getSingle();
        
        		if (s1.equals(s2))
        			System.out.println("同一个对象");
        		else
        			System.out.println("不是同一个对象");
        	}
        }

        对于懒汉式如果一个人使用没有问题,但是如果多个人使用这个程序时,就会出现安全问题。比如:两个人都在使用这个程序,如果第一个人调用时,在①处CPU切换到另外一个人,再进行判断时。s还是为空,这样第一个人和第二个人的都会创建一个对象。所以要将代码进行如下优化。
      • class Single
        {
        	private Single(){}
        	private static Single s = null;
        
        	public static Single getSingle()
        	{	
        		if (s==null)	//先判断引用是不是为空
        		{
        		
        			synchronized(Single.class)//防止第一次创建对象时多个人调用,产生安全问题
        			{
        				if(s==null)
        					//①
        					s = new Single();		
        			}
        		}
        		return s;
        	}
        }
        
        
        class SingleDemo 
        {
        	public static void main(String[] args) 
        	{
        		Single s1 = Single.getSingle();
        		Single s2 = Single.getSingle();
        
        		if (s1.equals(s2))
        			System.out.println("同一个对象");
        		else
        			System.out.println("不是同一个对象");
        	}
        }

        在以上的这两种方法中,开发中最常用的是饿汉式。因为简单并且不会产生安全问题,但是将懒汉式进行双重判断和加上锁机制以后也可以解决这个问题。加上双重判断主要是为了第二次执行的时候不再去判断锁,提高了程序的执行效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值