-------android培训、java培训、期待与您交流-------
01面向对象(Static关键字)
static关键字: 用于修饰成员(成员变量和成员函数)
被修饰后的成员具备以下特点:
随着类的加载而加载 随着类的消失而消失,说明它的生命周期最长。
优先于对象先存在 明确一点:静态是先存在,对象是后存在的。
被所有对象所共享
可以直接被类名调用(当成员被静态修饰后,就多了一个调用方式,除了可以被对象调用外,还可以直接被类名调用。 类名.静态成员)
实例变量和类变量的区别:
存放位置
类变量随着类的加载而存在于方法区中
实例变量随着对象的建立而存在于堆内存中
生命周期
类变量生命周期最长,随着类的消失而消失
实例变量生命周期随着对象的消失而消失
区别:类一进内存,可以给这个类产生n多对象,想什么时候建立对象就什么时候建立对象,可是,对象用完会消失,这个对象一消失,对象中的name也跟着消失(实例变量也跟着消失),而当类消失后,就无法创建对象了,所以,生命周期最长的是类,其次是对象,实例变量是跟着对象走的。
使用注意:
静态方法只能访问静态成员(静态先在,非静态还没在内存中,当然不能访问了)
非静态方法既可以访问静态也可以访问非静态
静态方法中不可以写this,super关键字
因为静态优先于对象存在,所以静态方法中不可以出现this
主函数是静态的
被static关键字修饰后就不在堆内存当中了,会被单独提取出来
特有内容随着对象存储(堆内存当中),共性内容(方法区,共享区,数据区)
class Person
{
String name;//成员变量,实例变量
static String country = "CN";//静态的成员变量,类变量 这个变量存在时没有对象,所以使用它只能用类名。所以多一种调用方式:类名调用。
public void show()
{
System.out.println(name+":::::"+country);
}
}
为什么不把所有成员都定义成静态的,什么数据是对象特有的,什么数据是对象共有的要区分的出来,因为这样它符合现实生活中的描述,还有一点,在开发中,如果你将所有的东西都变成静态,这些数据的生命周期会特别长:对象用完后,成员变量还在,这样会对内存的消耗很大。所以不建议定义过多的静态变量,什么时候定义:要区分的出来是不是被多个对象所共享,是就静态,不是就千万别静态。
本来对象就是用来访问非静态的。
静态有利有弊:
利处:对对象的共享数据进行单独空间的存储,节省空间,没有必要每一个对象中都存储一份。
可以直接被类名调用(因为静态在时只有类,没有对象,调用者就俩:一个类名,一个对象。没对象只能用类名来调用) 如果想使用一个类中的成员,一般情况下:建立那个类的对象,调用它里面的方法;那么这个类中没对象时,就得用类名调用。用类名调用,就得在成员里边定义几个静态成员
弊端:生命周期过长。
访问出现局限性(静态虽好,只能访问静态)
02面向对象(main函数)
public static void main(String[] args)
主函数:是一个特殊的函数,作为程序的入口,可以被jvm调用
主函数是被虚拟机调用,调用函数时都要往里边传与之对应的参数(实际参数)
虚拟机调用main时传啥?
jvm在调用主函数时,传入的是new String[0];
主函数的定义:
public:代表着该函数访问权限是最大的。
static:代表主函数随着类的加载就已经存在了。
void:主函数没有具体的返回值。
main:不是关键字,但是是一个特殊的单词,可以被jvm识别。
(String[] args):函数的参数,参数类型是一个数组,该数组中的元素是字符串,字符串类型的数组
字符串是最方便的数据
主函数是固定格式的:jvm识别。 只有args(arguments参数)这个可以改,这个是变量名,怎么起都行
public static void main(int x) 这叫做重载,不是主函数
03面向对象(静态什么时候使用)
什么时候使用静态?
要从两方面下手:
因为静态修饰的内容有成员变量和函数。
什么时候定义静态变量(类变量)呢?
当对象中出现共享数据时,该数据被静态所修饰。
对象中的特有数据要定义成非静态存在于对内存中。
为了增加程序的严谨性,为了更符合我们描述事物的本质,更贴切,就需要 用静态来修饰一下
什么时候定义静态函数呢(在设计时也能用)一定要背下来
当功能内部没有访问到非静态数据(对象的特有数据),那么该功能可以定义成静态的。
举例:
class Person
{
String name;
public void show() //没有访问到对象中的特有数据 name 就加static
{
System.out.println("haha");
}
}
class Person
{
String name;
public void show() // 绝对不能加static,因为下面那句输出语句中有访问到对象中的特有数据
{
System.out.println(name+"haha");
}
}
04面向对象(静态的应用—工具类)
静态的应用:
class Demo
{
public static void main(String[] args)
{
int[] arr = {3,4,1,8};
int max = 0;
for(int x=1;x<arr.length;x++) //数组最大值的获取
{
if(arr[x]>arr[max])
max = x;
}
System.out.println("max="+arr[max]);
}
}
————————————————————————
class Demo
{
public static void main(String[] args)
{
int[] arr = {3,4,1,8};
int max = getMax(arr);
System.out.println("max="+max);
}
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];
}
}
————————————————
每一个应用程序中都有共性的功能,可以将这些功能进行抽取,独立封装,以便复用
虽然可以通过建立ArrayTool的对象使用这些工具方法,对数组进行操作
发现了问题:
1,对象是用于封装数据的,可是ArrayTool对象并未封装特有数据。
2,操作数组的每一个方法都没有用到ArrayTool对象中的特有数据。
这时就考虑,让程序更严谨,是不需要对象的。
可以将ArrayTool中的方法都定义成static的。直接通过类名调用即可。
将方法都静态后,可以方便于使用,但是该类还是可以被其他程序建立对象的。
为了更为严谨,强制让该类不能建立对象。
可以通过将构造函数私有化完成。
05面向对象(帮助文档的制作 javadoc)
接下来,将ArrayTool.class文件发送给其他人,其他人只要将该文件设置到classpath路径下,就可以使用该工具类。但是,很遗憾,该类中到底定义了多少个方法,对方却不清楚,因为该类并没有使用说明书
开始制作程序的说明书。java的说明书通过文档注释来完成。
里面通常定义类的描述信息
/**
这是一个可以对数组进行操作的工具类,该类中提供了获取最值,排序等功能。
@author 张三
@version v1.1
*/
public class ArrayTool //如果一个类要想变成帮助文档,必须是public来修饰
{
/**
空参数构造函数
*/
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])
max = x;
}
return arr[min];
}
/**
给int数组进行选择排序
@param arr 接收一个int类型的数组。
*/
public static void selectSort(int[] arr)
{
for (int x=0; x<arr.length; 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;
}
/**
用于打印数组中的元素,打印形式是:[element1,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.print(arr[x]+"]");
}
}
}
class ArryToolDemo
{
public static void main(String[] args)
{
int[] arr = {3,1,87,32,8};
/*
ArrayTool tool = new ArrayTool();
int max = tool.getMax(arr);
System.out.println("max="+max);
tool.printArray(arr); 排序前
tool.selectSort(arr);
tool.printArray(arr); 排序后
*/
int max = ArrayTool.getMax(arr);
System.out.println("max="+max);
}
}
这个文档当中要体现的是你准备对外暴露的内容,那么,私有的是不会体现的,即使写了文档注释,javadoc也不提取,它会判断权限,只有两种权限才会被提取到文档当中去,一个叫做public,一个叫protected 被保护权限
一个类中默认会有一个空参数的构造函数,
这个默认的构造函数的权限和所属类一致。
如果类被public修饰,那么默认的构造函数也带public修饰符。
如果类没有被public修饰,那么默认的构造函数,也没有public修饰。
默认构造函数的权限是随着类的变化而变化的。
api帮助文档 应用程序接口
06面向对象(静态代码块)
格式:
static
{
静态代码块中的执行语句
}
特点:随着类的加载而执行,只执行一次。并优先于主函数。
用于给类进行初始化的。
(静态的都是随着类的加载而加载,而其他内容都有名字,可以被调用才执行,因为它是没有名字的,所以它随着类的加载完,里面的代码紧跟着就执行完了)
class StaticCode
{
static
{
System.out.println("a"); // 5.执行 7.不执行a了,因为静态代码块只执行一次
}
}
class StaticCodeDemo
{
static
{
System.out.println("b"); // 1.类一加载就执行静态代码块中的内容
}
public static void main(String[] args) // 3. 开始读主函数
{
new StaticCode(); //4.会将StaticCode这个class文件加载进内存
new StaticCode(); //6.又new一个
System.out.println("over"); // 8.
}
static
{
System.out.println("c"); // 2.
}
}
执行结果为 b c a over
class StaticCode
{
static
{
System.out.println("a");
}
public static void show()
{
System.out.println("show run");
}
}
class StaticCodeDemo
{
static
{
//System.out.println("b");
}
public static void main(String[] args)
{
StaticCode s = null; // 问:a是否有执行 这个类类型变量没有任何实体指向,这个变量存在就没有意义,所以这 //个时候还没加载,
s = new StaticCode(); //这个时候才加载
StaticCode.show(); // 这样也加载了
}//在用到这个类中的内容后才会被加载,
static
{
//System.out.println("c");
}
}
07面向对象(对象的初始化过程)
演示这些代码在内存中的哪一部分进行存储
class Person
{
private String name=“”;
private int age;
private static String country = "cn";
person(String name,int age)
{
this.name = name;
this.age = age;
}
{
System.out.println(name+".."+age);
}
public void setName(String name)
{
this.name = name;
}
public void speak()
{
System.out.println(this.name+"..."+this.age);
}
public static void showCountry()
{
System.out.println("country="+country);
method();//省略了person.
}
public static void method()
{
System.out.println("method run")
}
}
class
{
public static void main(String[] args)
{
Person p = new Person("zhangsan",20);//new时会将Person.class文件从硬盘当中通过java虚拟机将这个person.class文件加载进内存并开辟堆内存空间
P.setName("lisi");
}
}
1.先将类加载进内存。
2.静态代码块被执行。(静态优先于对象)
3.开辟空间。
4.初始化 属性初始化:1.默认初始化。2.显示初始化3.构造代码块初始化。4.构造函数(有针对性,是所有对象)初始 化。2优先级比3高
Person p = new Person("zhangsan",20);
该句话都做了什么事情?
1.因为new用到了Person.class。所以会先找到Person.class文件并加载到内存中。
2.执行给类中的static代码块,如果有的话,给Person.class类进行初始化。
3.在堆内存中开辟空间,分配内存地址。
4.在堆内存中建立对象的特有属性,并进行默认初始化。
5.对属性进行显示初始化。
6.对对象进行构造代码块初始化。
7.对对象进行对应的构造函数初始化。
8.将内存地址赋给栈内存中的p变量。
08面向对象(单例设计模式)
设计模式:解决某一类问题最行之有效的方法。
java中有23种设计模式
单例设计模式:解决一个类在内存只存在一个对象。
想要保证对象唯一:
1.为了避免其他程序过多的建立该类对象,先禁止其他程序建立该类对象
2.还为了让其他程序可以访问到该类对象,只好在本类中,自定义一个对象。
3.为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式。
这三部怎么用代码体现呢?
1.将构造函数私有化。
2.在类中创建一个本类对象
3.提供一个方法可以获取到该对象
对于事物该怎么描述,还怎么描述(描述不会变)。
当需要将该事物的对象保证在内存中唯一时,就将以上的三步加上即可。
这个是先初始化对象。
称为:饿汉式
Single类一进内存,就已经创建好了对象。
开发时一般用饿汉式。因为它安全简单:
class Single
{
private Single(){}
private static Single s = new Single(); // 静态方法访问静态成员 所以要加静态 类变量要私有化
public static Single getInstance() // 获取实例 因为要用类名调用,所以要静态
{
return s;
}
}
class SingleDemo
{
public static void main(String[] args)
{
Single ss = Single.getInstance();
}
}
09面向对象(单例设计模式方式二)
对象是方法被调用时,才初始化,也叫做对象的延时加载。
称为:懒汉式
Single类进内存,对象还没有存在,只有调用了getInstance方法时,才建立对象。
class Single
{
private static Single s = null;
private Single(){}
public static synchronized Single getInstance() //上一个锁,但是程序效率会变低
{ // 因为想要new对象时都要先判断一下是否为null
if(s==null)
-->A
-->B
s = new Single();
return s;
}
}
一个先初始化,一个后初始化
记住原则:定义单例,建议使用饿汉式
最终解决方案:
class Single
{
private static Single s = null;
private Single(){}
public static synchronized Single getInstance()
{
if(s==null)
{
synchronized(Single.class)
{
if(s==null)
s = new Single();
}
}
return s;
}
}