您的位置:首页 > 编程语言 > Java开发

Java基础之静态修饰符知识点总结

2017-12-07 11:45 661 查看
静态修饰的特点:
static是一个修饰符,用于修饰成员(成员变量和成员函数)。
1,静态成员随着类的加载而加载。
2,静态成员优先于对象存在。
3,静态成员被所有对象所共享
4,静态成员中多了一个调用方式,可以被类名直接调用。
静态使用的注意事项。
1,静态方法只能访问静态成员。
非静态方法既可以访问静态又可以访问非静态。
2,静态方法中不可以定义this,super关键字。
因为this代表是对象。而静态存在时,有可能没有对象。所以静态方法运行时,this是没有任何对象代表的。
简单说,先进内存的数据不可以访问后进内存的数据,可是后进内存数据可以访问先进内存的数据。
3,主函数是静态的。
静态:
好处:静态成员多了一种调用方式。可以直接被类名调用
格式 :类名.静态成员。也可以被对象调用。
弊端:静态方法只能访问静态成员,出现了访问局限性。
静态修饰的数据对象共享的数据,存放在方法区的静态区中。
非静态的数据,是每一个对象特有数据。存放在对象的所属的堆内存中。

例子1:静态修饰符static的用法实例。
[java] view plain copy package cn.itheima.day18;
class Person{
String name;
static String country = "CN";
public static void show(){
System.out.println("country="+country);
}
}
public class StaticDemo {
public static void main(String[] args) {
//静态成员多了一种调用方式。直接可以被类名所调用。
Person.show();
Person p = new Person();
p.name="zhangsan";
System.out.println(p.name);
Person p2 = new Person();
p2.name="lisi";
System.out.println(p2.name);
}
}

当成员变量被静态修饰后。
静态成员变量和非静态成员变量的区别:
1,静态变量也称为类变量,也就是直接可以被类名调用的变量。这个变量是所属于类的。
非静态变量成为成员变量,或者实例变量,是被对象调用的,是所属具体对象的。
2,静态变量随着类的加载而加载,也意味着随着类的消失而消失。生命周期最长。
实例变量,随着对象的创建而加载,随着对象的消失而消失。按照对象的生命周期而存在。
3,静态变量存储在方法区的静态区中。
实例变量存在于对象所属的堆内存中。
4,静态变量数据,被所有对象所共享。
实例变量是对象中的特有数据。
任何成员被访问使用,必须要被调用。如果是非静态成员,必须要被对象调用。在本类中调用是使用的是this。如果是静态成员,必须要被类名调用。只不过在书写时,可以省略。静态变量在静态区中也会进行默认初始化。

例子2:静态成员的调用方式。

[java] view plain copy package cn.itheima.day18;
class Demo{
int num1 = 3;
static int num2 = 5;
void show(){
System.out.println("num1="+this.num1);
System.out.println("num2="+Demo.num2);
}
static void method(){
System.out.println("num2="+Demo.num2);
}
}
public class StaticDemo2 {
public static void main(String[] args) {
Demo d = new Demo();
d.show();
d.method();
System.out.println("------------");
Demo.method();
}
}

什么时候使用static呢?
成员变量:
什么时候被静态修饰呢?
当该成员变量所存储的数据,每一个对象都是一样的,这时没有必要把该数据存储到每一个对象中,只要让所有对象共享该数据即可,这时成员就需要被static修饰。
当数据需要被对象共享时,就使用static修饰。这样可以对共享的数据节约内存。
成员函数:
当成员函数内并没有访问对象中的特有数据时,就将该方法定义成静态的。
简单说:该函数如果访问了成员变量,该函数就是非静态的。
该函数没有访问过成员变量,或者访问过静态的成员变量,那么为了程序的严谨性,将该方法定义成静态的。因为该方法不需要对象存在,既可以使用。

例子3:定义静态成员函数的实例演示。

[java] view plain copy package cn.itheima.day18;
class Person1{
String name;
static String country = "CN";
Person1(String name){
this.name = name;
}
public void show(){
System.out.println("name="+this.name);
}
public static void method(){
System.out.println("country="+Person1.country);
}
}
public class StaticDemo3 {
public static void main(String[] args) {
Person1 p1 = new Person1("aa");
p1.show();
Person1 p2= new Person1("bb");
p2.show();
Person1.method();
}
}

例子4:静态函数的实例演示。

[java] view plain copy package cn.itheima.day18;
/*  其中的每一个功能都没有对该类的对象的特有数据进行访问,
那么这些功能,就不需要对象调用。除了对象调用方式外,
还有一个类名调用方式。所以可以将这些功能都定义成static的。
这个类中的功能都被静态化后,只要使用类名调用即可。

但是其他程序在使用该类时,因为该类中有一个默认的构造函数,
所以其他程序还可以建立该类对象,而该类并不需要对象就可以
使用类中的成员。所以这个对象建立是没有意义的。为了提高程
序的严谨性。应该强制不让其他程序建立该类对象。

当该类中的属性或者行为都是静态的时候,该类创建对象是非常没有意义的。
所以就要强制不让其他程序建立对象,也就是将该类的构造函数私有化。
这样,你即使建立了该类对象,也没有办法初始化。
*/
public class ArrayTool {
private ArrayTool(){}  //不让其他的程序创建该类文件
//对int类型的数组进行排序。从小到大。
public static void sort(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);
}
}
}
}
//给数组进行换位操作。
private static void swap(int[] arr, int x, int y) {
int temp = arr[x];
arr[x] = arr[y];
arr[y]=temp;
}
//将int数组转换成字符串。
public static String arrToString(int[] arr){
String str="[";
for(int x = 0;x<arr.length;x++){
if(x!=arr.length-1){
str=str+arr[x]+",";
}else {
str = str+arr[x]+"]";
}
}
return str;
}
//获取数组中的最大值。
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];
}
}
---------------------------------
package cn.itheima.day18;
public class ArrayToolDemo {
public static void main(String[] args) {
int[] arr = {3,1,4,5};
String str1 = ArrayTool.arrToString(arr);
System.out.println(str1);
ArrayTool.sort(arr);
String str = ArrayTool.arrToString(arr);
System.out.println(str);
}
}

主函数静态的,说明主函数只能直接访问静态的成员。
public static void main(String[] args)
public: jvm调用的函数必须权限足够大。所以被public修饰。
static: 主函数随着类的加载而加载,jvm不需要创建该类对象既可以完成对该函数的调用,所以是静态的。
void: 主函数没有返回值。
main: 函数名,是固定的,jvm认识。
(String[]args):主函数的参数列表,参数类型是:一个字符串数组类型的参数。
args:参数名称。
主函数有参数,那么jvm调用的时候,就需要传入相对应的实际参数。
问:jvm调用主函数时,到底传入了什么呢?
//System.out.println(args);//[Ljava.lang.String;@de6ced
//[Ljava.lang.String;@de6ced:通过这个结果看到,args指向了一个具体的数组实体。
//而且该数组中的元素是String类型的。
System.out.println(args.length);//0
//通过两个输出语句,就可以验证,jvm给主函数传递的实际参数是: new String[0];
这是jvm传入的默认值。但是没什么用,所以我们在使用main时,可以自定义该主函数数组中的元素。

例子5:主函数分析的实例演示。


[java] view
plain copy

package cn.itheima.day18;

public class MainDemo {

int x = 4;

public static void main(String[] args) {

//System.out.println(args);//[Ljava.lang.String;@de6ced

//[Ljava.lang.String;@de6ced:通过这个结果看到,args指向了一个具体的数组实体。

//而且该数组中的元素是String类型的。

System.out.println(args.length);//0

//通过两个输出语句,就可以验证,jvm给主函数传递的实际参数是: new String[0];

/*

这是jvm传入的默认值。

但是没什么用,所以我们在使用main时,可以自定义该主函数数组中的元素。

*/

String arr[]={"haha","hehe","heihei","xixi"};

new MainDemo().show();

Test.main(arr);

}

public void show(){

System.out.println("x="+x);

}

}

class Test{

public static void main(String[] args){

for(int a=0;a<args.length;a++){

System.out.println(args[a]);

}

}

}

静态代码块。
格式:
static{
code..;
}
作用:当类在加载进内存时,如果需要进行一些内容的执行,完成一个类的初始化。就需要使用静态代码块来完成,给类进行初始化。
执行特点:当类被加载时,静态代码就执行了,而且只执行一次。而且优先于main函数执行。

例子6:静态代码块的实例演示。

[java] view plain copy package cn.itheima.day18;
//运行顺序:静态代码块--->
1f14e
;构造代码块--->构造函数
class StaticCode{
{   //静态代码块
System.out.println("AAAAA");
}
static{   //静态代码块
System.out.println("a");
}
public StaticCode() {
System.out.println("StaticCode");
}
static void show(){
System.out.println("show run");
}
}
public class StaticCodeDemo {
static {
System.out.println("b");
}
public static void main(String[] args) {
System.out.println("d");
//StaticCode.show();
new StaticCode();
System.out.println("e");
}
static{
System.out.println("c");
}
}
//打印结果:
/*
* b  c  d  a  AAAAA  StaticCode  e
*/

设计模式:就是解决某类问题最行之有效的解决方案,设计模式是一种思想。
java中总结出来23种设计模式。
单例设计模式(23种设计模式之一):
解决的问题:保证一个类在内存中的只存在一个对象。
简单说:保证一类在内存中的对象唯一性。
应用场景:比如配置文件。A要使用配置文件对象。B程序也要使用配置文件对象。希望A程序对配置数据修改后,B程序可以直接使用,那么就需要A程序,和B程序使用的同一个对象.
如何保证一个类在内存中的对象唯一性呢?
1)为了控制该类的对象建立,不让其他程序建立该类的对象。
2)在本类中自定义一个本类对象。
3)对外提供获取该对象的方式即可。
代码如何实现呢?
1)可以将构造函数私有化。这样对方程序创建就无法初始化。已达到不允许,其他程序创建对象的目的。
2)在本类中,通过new创建一个本类对象。
3)提供一个公共的方法返回该对象,方便于其他程序获取该对象。
代码体现具体:
1)私有化构造函数。
2)创建一个私有并静态的本类的对象。
3)创建一个公共的static方法返回该对象。

例子7:单例模式的实例演示。

[java] view plain copy package cn.itheima.day18;
//饿汉式
class Single{
private static Single s = new Single();
private Single(){}
public static Single getInstance(){
return s;
}
}
//需要保证Demo类在内存中的对象唯一性。只要保证一个类的对象唯一性
class Demo3{
private int num = 4;
private static Demo3 d = new Demo3();//类一加载,该对象就已经存在了。
private Demo3(){}
public static Demo3 getInstance(){
return d;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}
public class SingleDemo {
public static void main(String[] args) {
/*Single ss = Single.getInstance();
Single ss1 = Single.getInstance();
System.out.println(ss==ss1);*/
Demo3 d1 = Demo3.getInstance();
Demo3 d2 = Demo3.getInstance();
d1.setNum(10);
d2.setNum(20);
System.out.println("d1.num="+d1.getNum());
System.out.println("d2.num="+d2.getNum());
}
}

对象的延迟加载方式。这种方式看上去很美,但是当并发访问getInstance方法时,容易出现安全隐患(线程安全问题)
懒汉式

例子8:单例设计模式(懒汉式)的实例演示。

[java] view plain copy package cn.itheima.day18;
//饿汉式
class Single1{
private static Single1 s = null;
private Single1(){}
public static Single1 getInstance(){
if(s==null){
s =  new Single1();
}
return s;
}
}
public class SingleDemo1 {
public static void main(String[] args) {
Single1 ss = Single1.getInstance();
Single1 ss1 = Single1.getInstance();
System.out.println(ss==ss1);
}
}

使用时,一般使用饿汉式。
而面试时,都面试懒汉式,因为涉及的技术细节很多。
面向常见问法:请写出一个单例延迟加载的示例。这个考的就是懒汉式.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: