JAVA笔记-Static与Final详解笔记

static 成员变量

静态变量属于类的变量,所有类的实例共享的同一个变量。

直接使用类名读写这个变量

应用场景:

案例:

public class Demo04 {

public static void main(String[] args) {

//静态变量属于类的 变量

//直接使用类名读写这个变量

Hoo.z = 10;

int n = Hoo.z;

System.out.println(n);//10

//实例变量x,y是属于对象的变量

//创建对象以后才能使用实例变量

//每个对象都有自己的实例变量

Hoo h1=new Hoo();//(x,y)

Hoo h2=new Hoo();//(x,y)

//使用对象范围对象的实例变量

h1.x = 5;

h1.y = 6;

//测试:h1有自己的属性(5,6)

// h2有自己的属性(0,0)

// h1,h2 共享同一个 Hoo.z

System.out.println(h1);

System.out.println(h2);

//只有所有对象共享的同一个变量,

//才能使用静态修饰

}

}

class Hoo{

int x, y;

static int z;

public String toString(){

return x+”,”+y+”,”+z;

}

}

静态方法

静态方法是属于类的方法,一般使用类名直接调用静态方法。

静态方法与对象方法差别:

· 静态方法中没有隐含参数this(当前对象),不能调用当前对象的属性和方法。

· 非静态方法(对象的方法)在执行期间将调用方法的对象传递给this(当前对象)变量,可以访问当前对象的属性和方法。

使用原则:

如果一个方法的计算过程使用了当前对象的数据,就不能使用静态方法;

相反如果没有使用当前对象的数据,就可以声明为静态方法。

提示:程序中大多使用对象的方法(非静态方法),工具方法和工厂方法使用静态较多。

常用工具方法(静态方法):

Math.sqrt(num)

Math.sin()

Math.cos()

Arrays.toString()

Arrays.sort()

Arrays.fill()

静态方法:

对象方法:

案例代码:

public class Demo05 {

public static void main(String[] args) {

/*

* 静态方法

*/

//静态方法是属于类的方法,用于类名

//调用方法: 类名.方法()

Point p1 = new Point(3, 4);

Point p2 = new Point(6, 8);

//静态方法执行期间没有 this(当前对象)!!!

//静态方法不能访问当前对象的数据!!

double d=Point.distance(p1, p2);

System.out.println(d); //5.0

//在对象上调用非静态方法

//非静态方法有this!!!

//可以访问this(当前对象)中的数据

d = p1.distance(p2);

System.out.println(d); //5.0

    //结论:如果一个方法的计算过程使用
    //了当前对象的数据,就不能使用静态
    //方法,相反如果没有使用当前对象的
    // 数据,就可以声明为静态方法。
}

}

class Point{

int x,y;

public Point(int x, int y) {

this.x=x; this.y=y;

}

/*
 * Point类中的非静态方法
 * 包含隐含参数this,引用调用方法的对象
 */
public double distance(
    /* Point this */ Point p2){
    //有一个隐含的引用this,引用调用方法
    //当前对象,就可以使用这个对象的数据
    int a = this.x-p2.x;
    int b = this.y-p2.y;
    int c2= a*a+b*b;
    return Math.sqrt(c2);
}

/*
 * 计算过程只用到参数的数据, 所以定义为
 * 静态方法。
 * 计算两个点p1 和p2 之间的距离(勾股定理)
 */
public static double distance(
    Point p1, Point p2){
    int a = p1.x-p2.x;
    int b = p1.y-p2.y;
    int c2 = a*a+b*b;
    return Math.sqrt(c2);
}

}

静态代码块

静态代码块:

是类级别的代码块

在类的加载期间执行,只执行一次

用于处理只初始化一次的数据,如:读取图片数据,等。

案例:

public class Demo06 {

public static void main(String[] args) {

Noo n1 = new Noo();

Noo n2 = new Noo();

}

}

class Noo{

/*

* 类中可以声明“代码块”

* 创建对象时候执行代码块

*/

{

System.out.println(“HI”);

System.out.println(“代码块”);

}

/*
 * 静态代码块
 * - 是类级别的代码块
 * - 在类的加载期间执行,只执行一次
 * - 用于处理只初始化一次的数据,如:读取
 *   图片数据。
 */
static {
    System.out.println("静态代码块");
    System.out.println("静态代码块2");
}

}

final 关键字

final变量

final 修饰变量

初始化以后不能“再”改变的变量。

final 修饰局部变量

可以初始化一次!!初始化以后不能“再”改变

案例:

int a = 5;

a = 8;//不是final的变量可以修改值

System.out.println(a);

final int b = 5;//初始化

//b = 8;//编译错误,不能再改变

final int c;

c = 5;//可以初始化一次!!

//c = 8;//编译错,但是不能再次改变值!!

System.out.println(c);

final 修饰的引用变量

可以初始化一次!!初始化以后不能“再”改变。

注意:这里不能改变的是引用变量与对象的引用关系,对象的成员可以任意改变!

案例:

final int[] ary = {3,4,5};

//ary = null;//编译错,但是不能再次改变值!!

ary[0]=5;//可以改变对象内容(数组元素)

System.out.println(ary[0]);//5

final 的方法参数

方法参数也是局部变量,可以使用final声明

方法的参数是在调用方法传递参数时候初始化的,初始化以后在方法内部不能再次改变。

案例:

test(4,5);//调用方法,初始化参数变量

public static void test(

final int a, int b){

b = 2;

//a = 5;//初始化以后不能再修改

System.out.println(a+”,”+b);

}

final的属性

1.final 修饰对象的属性,这个属性不能自动初始化,必须手动初始化。

可以直接赋值初始化

也可以使用构造器进行初始化

2.final属性初始化以后就不能再改变了。

3.final 修饰的属性,仍然是实例变量,还是每个都有一个的属性。

4.final修饰属性,当final变量是基本数据类型以及String类型时,如果在编译期间能知道它的确切值,则编译器会把它当做编译期常量使用。见文章最后的代码说明。

注意:static 修饰的成员变量,是属于类的变量,是全体共享的同一个变量,与final属性不同。

案例:

//测试:

Roo r1 = new Roo(5);

r1.a = 8;//普通属性可以改变

//r1.b = 7;//编译错误,不能改变final属性

Roo r2 = new Roo(6);

//证明每个对象都有属性b

System.out.println(r1.b+”,”+r2.b);

//类

class Roo{

int a;

final int b;

public Roo(int b) {

this.b = b;

}

}

static final 声明的是常量

对于软件中的不变的常数可以声明为常量

Java 利用“编译擦除”方式替换常量为常数

编译以后原有的常量就被替换为常数

这样可以在运行期间避免到类中读取常量数值,提高程序的运行效率。

案例:

public class Demo09 {

public static void main(String[] args) {

/*

* 测试常量的“编译擦除”技术

* Java 的编译器在编译期间将常量

* K.PI 擦除替换为 3.1415926

* 在运行期间程序无需加载 K 类,

* 也能运行,并且输出 3.1415926

*/

System.out.println(K.PI);

K k = new K();

}

}

class K{

public static final double PI=3.1415926;

static {

System.out.println(“Load K”);

}

}

final方法

final关键字修饰的方法不可以被重写。

使一个方法不能被重写的意义在于:防止子类在定义新方法时造成的“不经意”重写。

注意:在实际开发中是很少使用final修饰方法。

final类

final关键字修饰的类不可以被继承。

final class Foo { }

class Goo extends Foo { }

JDK中的一些基础类库被定义为final的,例如:String、Math、Integer、Double 等等。

使一个类不能被继承的意义在于:可以保护类不被继承修改,可以控制滥用继承对系统造成的危害。

经典题目:

class MyString extends String(){}

答案:编译错误,因为String是final类不能被继承子类!

注意:在实际开发中是很少使用final修饰类

测试:Final修饰的属性会在类初始化时“编译擦除”,会替换成常数。

package demo;
class Price {
//  static{
//      System.out.println("Static块");
//  }
    //类成员INSTANCE是Price实例
    static Price INSTANCE = new Price(2.8);//1
    //默认价格initPrice
    static  double initPrice = 20;//2
    //当前价格
    double currentPrice;
    //构造函数
    public Price(double discount){
                //super();

                System.out.println("执行了构造函数 initPrice:"+ initPrice);
                currentPrice = initPrice - discount;
    }
}
public class PriceTest {
    public static void main(String[] args) {
            System.out.println(Price.INSTANCE.currentPrice);//3
            Price p = new Price(2.8);//4
            System.out.println(p.currentPrice);
}
}

输出结果如下:

执行了构造函数 initPrice:0.0

-2.8

执行了构造函数 initPrice:20.0

17.2

分析:

在标记3处第一次用到Price类时,程序开始对Price类进行初始化,初始化类分为两个阶段:

第一个阶段:系统为Price的变量分配内存空间并赋予默认值;即INSTANCE = null,initPrice = 0.0,currentPrice=0.0;

第二阶段:按初始化代码的排列顺序对类变量进行初始化;程序依次对他们进行赋值。先对INStANCE赋值(new Price(2,8)),d调用构造器(跳过了正常的初始化顺序),将2.8传给discount局部变量,正常情况下应是先static Price INSTANCE = new Price(2.8);,再执行static double initPrice = 20;,但因有new Price(2.8)调用了构造方法,所以跳过了正常初始化,即static double initPrice = 20;语句并没有执行,也就是说通过new跳过其他的初始化,直接执行了构造器初始化,而此时initPrice并没有初始化,即是默认值0.0,currentPrice=-2.8。接着对inintPrice赋值为20.所以执行标记4处时,两个static变量都已经初始化过了,不会再初始化,此时new Price(2.8)调用构造方法,initPrice = 20.0,所以currentPrice为17.2.

若将标记2处改为:final double initPrice = 20;//2,输出的结果则发生了变化:

执行了构造函数 initPrice:20.0

17.2

执行了构造函数 initPrice:20.0

17.2

这是因为:

**当final变量是基本数据类型以及String类型时,如果在编译期间能知道它的确切值,则编译器会把它当做编译期常量使用。

因为initPrice的值是可以确定的,所以编译器在编译期间将它看做是常量了**

类的final变量和普通变量有什么区别?

  当用final作用于类的成员变量时,成员变量(注意是类的成员变量,局部变量只需要保证在使用之前被初始化赋值即可)必须在定义时或者构造器中进行初始化赋值,而且final变量一旦被初始化赋值之后,就不能再被赋值了。

  那么final变量和普通变量到底有何区别呢?下面请看一个例子:

public class Test {

public static void main(String[] args) {

String a = “hello2”;

final String b = “hello”;

String d = “hello”;

String c = b + 2;

String e = d + 2;

System.out.println((a == c));

System.out.println((a == e));

}

}

  大家可以先想一下这道题的输出结果。为什么第一个比较结果为true,而第二个比较结果为fasle。这里面就是final变量和普通变量的区别了,当final变量是基本数据类型以及String类型时,如果在编译期间能知道它的确切值,则编译器会把它当做编译期常量使用。也就是说在用到该final变量的地方,相当于直接访问的这个常量,不需要在运行时确定。这种和C语言中的宏替换有点像。因此在上面的一段代码中,由于变量b被final修饰,因此会被当做编译器常量,所以在使用到b的地方会直接将变量b 替换为它的 值。而对于变量d的访问却需要在运行时通过链接来进行。想必其中的区别大家应该明白了,不过要注意,只有在编译期间能确切知道final变量值的情况下,编译器才会进行这样的优化,比如下面的这段代码就不会进行优化:

public class Test {
    public static void main(String[] args)  {
        String a = "hello2";
        final String b = getHello();
        String c = b + 2;
        System.out.println((a == c));

    }

    public static String getHello() {
        return "hello";
    }
}

  这段代码的输出结果为false。

时间: 2024-10-16 09:00:55

JAVA笔记-Static与Final详解笔记的相关文章

Java下static关键字用法详解

Java下static关键字用法详解 本文章介绍了java下static关键字的用法,大部分内容摘自原作者,在此学习并分享给大家. Static关键字可以修饰什么? 从以下测试可以看出, static 可以修饰: 1. 语句块 2. 成员变量(但是不能修饰局部变量) 3. 方法 4. 接口(内部接口) 5. 类(只能修饰在类中的类, 即静态内部类) 6. jdk 1.5 中新增的静态导入 那么static 修饰的表示什么呢? 当创建一个类时,就是在创建一个新类型,描述这个类的对象的外观和行为,除

java中static{}语句块详解

1.当一个类中有多个static{}的时候,按照static{}的定义顺序,从前往后执行: 2.先执行完static{}语句块的内容,才会执行调用语句: 示例二 public class TestStatic{    static{        System.out.println(1);    }    static {        System.out.println(2);    }    static {        System.out.println(3);    }    p

ava下static关键字用法详解

Java下static关键字用法详解 本文章介绍了java下static关键字的用法,大部分内容摘自原作者,在此学习并分享给大家. Static关键字可以修饰什么? 从以下测试可以看出, static 可以修饰: 1. 语句块 2. 成员变量(但是不能修饰局部变量) 3. 方法 4. 接口(内部接口) 5. 类(只能修饰在类中的类, 即静态内部类) 6. jdk 1.5 中新增的静态导入 那么static 修饰的表示什么呢? 当创建一个类时,就是在创建一个新类型,描述这个类的对象的外观和行为,除

hadoop 学习笔记:mapreduce框架详解

hadoop 学习笔记:mapreduce框架详解 开始聊mapreduce,mapreduce是hadoop的计算框架,我 学hadoop是从hive开始入手,再到hdfs,当我学习hdfs时候,就感觉到hdfs和mapreduce关系的紧密.这个可能是我做技术研究的 思路有关,我开始学习某一套技术总是想着这套技术到底能干什么,只有当我真正理解了这套技术解决了什么问题时候,我后续的学习就能逐步的加快,而学习 hdfs时候我就发现,要理解hadoop框架的意义,hdfs和mapreduce是密不

javascript事件详解笔记

javascript事件详解笔记: 一.事件流 1.事件流: 描述的是页面中接受事件的顺序,有事件冒泡.事件捕获两种. 2.事件冒泡: 由最具体的元素接收,然后逐级向上传播到最不具体的元素的节点(文档). 3.事件捕获: 最不具体的节点先接收事件,而最具体的节点应该是最后接收事件. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>事件</title&

canvas绘图详解笔记(一)

声明一下:这里我不会用太多文字去详解介绍canvas是什么,相信了解过canvas的人都知道它的魅力所在,如果你对canvas还比较陌生的话,建议可以查阅相关资料了解一下.这里我将对canvas绘图详解课程做一次详细的笔记,方便大家和自己日后可以学习.那么接下来就是直接进入笔记内容的学习: 首先创建一个canvas元素,我们只需要在html文件中加入这么一句代码: <canvas id="canvas">当前浏览器不支持canvas,请更换浏览器使用!</canvas

nginx配置文件详解笔记

web运维第一篇:nginx配置文件详解笔记#定义Nginx运行的用户和用户组user www www;#nginx进程数,建议设置为等于CPU总核心数.worker_processes 8;#全局错误日志定义类型,[ debug | info | notice | warn | error | crit ]error_log /var/log/nginx/error.log info;#进程文件pid /var/run/nginx.pid;#一个nginx进程打开的最多文件描述符数目,理论值应

伪静态详解笔记

1.检测Apache是否支持mod_rewrite 通过php提供的phpinfo()函数查看环境配置,通过Ctrl+F查找到"Loaded Modules",其中列出了所有 apache2handler已经开启的模块,如果里面包括"mod_rewrite",则已经支持,不再需要继续设置. 如果没有开启"mod_rewrite",则打开目录 您的apache安装目录"/apache/conf/" 下的 httpd.conf 文

java中的io系统详解

java中的io系统详解 分类: JAVA开发应用 笔记(读书.心得)2009-03-04 11:26 46118人阅读 评论(37) 收藏 举报 javaiostreamconstructorstringbyte 相关读书笔记.心得文章列表 Java 流在处理上分为字符流和字节流.字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符.字符数组或字符串,而字节流处理单元为 1 个字节,操作字节和字节数组. Java 内用 Unicode 编码存储字符,字符流处理类负责将外部的其他