Java学习笔记(一)

在知乎上看到一篇文章讲解Java中的这两个关键字,原文🔗:https://zhuanlan.zhihu.com/p/24373135

面向对象是一种编程思想这个我知道,C语言不是面向对象的编程语言,Java、C++是面向对象的编程语言我也知道,但是我就是没想过为什么?今天才能描述出来:面向对象的语言是指编程语言提供了一种机制,使我们可以用比较简洁的语法表达数据的抽象和封装。

PostgreSQL这个用C语言写的数据库的源码中就有很多用struct的嵌套来模拟class的继承,这也是一种面向对象的思想,但是C语言就不是一种面向对象的语言,因为它并没有提供一种简洁的语法去表达数据的抽象和封装。

static关键字

background:

C++是可以定义全局变量、全局函数的,很多脚本语言,虽然是面向对象,但是也可以在类之外声明变量、定义函数、执行操作。
python和Scala就是比较灵活的语言,某个具体的操作可以脱离函数直接运行;
C++就严谨些,需要封装在函数中;
Java就更严格,Java总要求所有的函数都必须定义在一个类里,函数不能脱离类单独存在。
灵活和严谨各有利弊:太过灵活不易于掌握,比如Scala内部分裂成两个流派,一派把Scala作为Java的改进,另一派完全使用函数式编程。关于两个流派的区别🔗:https://blog.csdn.net/tao_wei162/article/details/84854702
Java语法的死板意味着更少的歧义,但是缺点也很多。

有些变量和函数实在是没有必要定义在一个class中,比如sin(),把它放在哪个类里合适呢?于是Java把这些数学函数都封装在一个Math类中,问题来了,那么这个类应该如何被定义?如果这样写:

class Math
{  public double sin(double x){/* code goes here*/}

那么调用的时候new Math().sin(x) 每次只能通过创建一个Math的对象来调用这个函数,本来一个可以全局存在的函数,非得这样调用,it doesn’t make sense!语言设计者考虑到这个问题,于是引入了static关键字。

text:

当我们在一个函数或者变量前面加上static限制以后,就可以在不创建一个对象的情况下,直接使用类里面的函数或者变量了:

class Math
{  public static double sin(double x) {/*code goes here*/}
Math.sin(x);

编程语言的关键字是有它内在的逻辑的,不要去死记硬背!!!
就像static是出现了类似于这样一个情况才出现的,并不是没事闲的就弄了一个难为人。
但是实际上写的时候要是满屏都是Math.sin(x);也不好,于是设计者们把主意打到了import那里,能不能把这些本来就是全局函数、全局常量的值导入当前文件中,好像它本身被封装到类里一样?
于是出现如下:

import static java.lang.Math.*;
public class Main {
    public static void main(String args[]) {
        System.out.println(sin(PI / 2));
    }
}
disadvantages:

本来这样就可以了,但是Java中有一个不太好的品味,关键字重用。


static关键字还可以用来定义静态代码块。static块可以置于类中的任何地方,类中可以有多个static块。在类被初次加载时,会按照static块的顺序来执行每个static块,并且只会执行一次。

这种与类加载有关的逻辑,显然应该甩锅给ClassLoader。比如 ClassLoader在加载一个类的时候,调用类中的static onLoad()方法,也比静态代码块这种引起混淆的语法好。这样的设计才会显得清晰。静态代码块是什么鬼!?这显然是一个关键字复用的错误例子。
我们没办法改变这种设计,只能去适应。记住这个用法吧。

static当然不能使用this和super
static函数就是全局函数,为了满足强对象的要求才不得不挂载在一个class中,本身和这个类没有关系。但是static也不能免费挂载,好处就是类成员对象在调用的时候不用写类名了。

class Example {
    public static void sayHello() {
        System.out.println("Hello, everybody~");
        // 这个当然不能用。static函数与其挂靠的那个类的对象没有任何关系。
        // static函数是全局唯一的。
        // this.sayBye();
    }   

    public void sayBye() {
        System.out.println("Good Bye~");
    }   

    public void saySomething() {
        // 唯一的一点好处,大概就是成员函数里这样三种写法都是OK的。
        // 但这个没卵用。我更喜欢Java只保留第三种写法,免得大家误会。
        this.sayHello();
        sayHello();
        Example.sayHello();
        this.sayBye();
    }

final关键字

text:

final用在类前类不能被继承,用在方法前不能被覆写。可以避免混乱的继承。

// 想创建一个自己的String类是不行的。因为String是final的。
class MyString extends String {}
class A { 
    public final void f() {
    }   

    // 这里是OK的,只是一次重载
    public final void f(int a) {
    }   
}

class B extends A { 
    // 会报错,说f是final的,不能覆写
    public void f() {
    }   
}
disadvantages:

基本用法:
对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。

//基本用法

final int a = 1;
        a += 2; // 会报错,我们不能修改一个final变量
//混淆之处
public class Hello {
    public static void main(String args[]) {
        String a = "go die, ";
        final String b = "final";
        String c = "go die, " + b;
        String d = a + b;
        String e = "go die, final";
        System.out.println(e == c); //true,比较两个变量是否指向同一个对象
        System.out.println(e == d); //false
        System.out.println(c.equals(d));//true,比较两个字符串的值是否相同
    }   
}     

在编译阶段,变量c其实已经是"go die, final"了,c和e是指向了常量池中的同一个字符串,也就是“go die, final"。所以它们其实是同一个对象。但是d却是运行时生成的,b 在编译阶段就已经被当作常量“final” 去做下面的编译了,并不引用常量池中的"go die, final"这个字符串,所以,虽然它们的值相同,但e和d并不是同一个对象。这和C++中编译时const变量转成编译时常量如出一辙。

final关键字被用来当做const用,实在不是个好的品味。当然,const这个关键字是保留字,就是说在Java中虽然现在没用,但不保证以后不会用。你是不能拿这个词来当变量名的。

如果一个变量在整个执行阶段不会被修改,那么加上final进行修饰是一个好的编程习惯。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值