[Java]Java学习笔记(二)——类的基本语法

java 类的基本语法大都与其他语言一样,就不再赘述了,将那些不太一样的地方列为零碎要点,如下。其他的高级部分,接下去会另起一篇。

零碎要点

1、使用 final 来创建常量。
虽然 Java 保留了 const 关键字,但暂未使用。

2、变量的参数传递一直都是值传递
测试如下:

package com.go.java.test;

public class Val {
    private int a;

    public Val(int v)
    {
        a = v;
    }

    public int GetVal()
    {
        return a;
    }
}
package com.go.java.test;


public class Test {

    public static void main(String[] args) {
        Val a = new Val(1);
        System.out.println(a.GetVal());
    }

    static void Fun(Val v) {
        Val b = new Val(2);
        v = b;
    }
}

输出为 1

显然,这值得批评,java 的效率,估计被这个拖累不少。

3、不合法的规则:
native 方法可以绕过 Java 语言的存取控制机制,进行某些操作。
如 System 类里的 in、out、err 声明分别为:

public final static InputStream in = null;
public final static PrintStream out = null;
public final static PrintStream err = null;

但在 set 函数中,却对 final 变量的值进行了修改,况且还是用与 Java 不和的引用参数方式进行修改:

public static void setIn(InputStream in) {
    checkIO();
    setIn0(in);
}

public static void setOut(PrintStream out) {
    checkIO();
    setOut0(out);
}

public static void setErr(PrintStream err) {
    checkIO();
    setErr0(err);
}

这种做法,我只能说请尽量不要这样用,除非。。。
Java 的 System 类是不允许实例化的,声明为 public final class,相比而言,C# 的做法更为合理,独立出一个 Console 类,将 Console 类定义为 static 类,成员也都定义为 static,不允许继承又不能实例化。

Java 6 之后也引入了 Console 类,但只是用于密码读取。

4、static 的使用与 C# 基本一致,例外的是类的 static 成员可以用类对象调用。
又一个不合理的设计。还是那句话,建议不要使用。

5、Java 与 C# 相同,每个类都可以有 主函数,多个类都有主函数时,需要指定其中一个为入口函数。在 java 里这样做比较方便,所以在类的主函数里进行类的单元测试,和在外面进行单元测试的写法是差不多的。
在 C# 习惯用 NUnit,在 Java 里还真不习惯用这种写法,还是使用 JUnit 吧。

6、this 的使用:
(1)当成员函数的参数与类成员变量名冲突时,用于区分。
(2)在构造函数中调用另一个构造函数。
比如有构造函数 A(int x, int y);A(int x)
那么我们可以在第二个构造函数中使用 this(x, 0); 这样的方式来简化代码。
当然这种方式也可以提取出一个私有函数来实现。

7、初始化块:
无论是 C++ 或 C#,我们都可以在 成员变量定义时直接赋予一个不涉及到其他变量的值,在 Java 里,可以在独立到初始化块中执行这个赋值操作。

Java 里,有普通变量初始化块和静态变量初始化块,允许所有可以在函数内部出现的语法功能。

package com.go.java.test;

import java.util.Scanner;

public class Init {
    int a;
    static int b;

    {
        a = 1;
    }

    static
    {
        Scanner in = new Scanner(System.in);
        System.out.println("set b = ?");
        b = in.nextInt();
        System.out.println(b);
        in.close();
    }

}
package com.go.java.test;


public class Test {

    public static void main(String[] args) {

        new Init();

//      Val a = new Val(1);
//      System.out.println(a.GetVal());
    }

    static void Fun(Val v) {
        Val b = new Val(2);
        v = b;
    }
}

控制台显示

set b = ?
2
2

如果我们直接使用 Java Init调用上面的类 Init,上面控制台那些也会照样执行,不过,会提示 “main is not define”。解决的方式是在 static 块的代码最后加上 System.exit(0);
这不是与那些借助漏洞实现那些没有主函数的 C 代码是同种性质吗!
还是那句:不要使用这种写法。

8、对象的析构处理:
Java 可以为任何一个类提供 finalize 方法,这样,在垃圾回收该对象前,会先调用这个方法。然而,并不推荐使用这个方法来关闭文件或释放句柄等,因为我们并不能确定该方法会在什么时候被调用。

另外还有个名为 System.runFinalizersOnExit(true); 的方法能够确保 finalize 方法在 Java 退出前被调用,但该方法并不安全,也不推荐使用。

有一种替代的方法:
使用方法 Runtime.addShutdownHook(Thread hook) 添加关闭钩,该方法会在 Java 程序退出前调用,

package com.go.java.test;


public class Test {

    public static void main(String[] args) {

        Thread one = new Thread() {
            public void run() {
                System.out.println("shut down thread one");
            }
        };

        Runtime.getRuntime().addShutdownHook(one);

        System.out.println("start thread one");

//      new Init();

//      Val a = new Val(1);
//      System.out.println(a.GetVal());
    }

    static void Fun(Val v) {
        Val b = new Val(2);
        v = b;
    }
}

然而有些资源需要立即释放,这时,我们就需要使用一个 close() 方法来执行,使用的方法有两种,一种是在 try-catch-finally 的 finally 块中调用 close() 方法,另一种是 实现 Closeable 接口,这样就无需 finally 块了(不过此时如果 close 函数执行出错,抛出的是 IOException),在try 块执行完成或出错时,都会执行 close() 方法。

相比而言,Go 使用 defer 来执行类似的工作显得比较简便、灵活。

9、最后,再说说 Java 的问题:类的默认成员属性居然是 protected,这又和 C++ / C# 不同了。

访问属性的规则:
private:对本类可见。
public:对所有类可见。
protected:对本包可见。默认。

虽然一直强调不要省去访问属性关键字,但还有一些人总会遗漏。正如 《Java核心技术 · 基础知识》里提到的,Java 自己的库中都存在这种问题:

/**
 * This represents the warning message that is
 * to be displayed in a non secure window. ie :
 * a window that has a security manager installed that denies
 * {@code AWTPermission("showWindowWithoutWarningBanner")}.
 * This message can be displayed anywhere in the window.
 *
 * @serial
 * @see #getWarningString
 */
String      warningString;

为什么说这样做有问题呢,下面是 sublime text 的搜索结果,warningString 并不可以直接被赋值。

 1380      public final String getWarningString() {
 1381:         return warningString;
 1382      }
 1383  
 1384      private void setWarningString() {
 1385:         warningString = null;
 1386          SecurityManager sm = System.getSecurityManager();
 1387          if (sm != null) {
 ....
 1392                  // for getting the property! We don't want the
 1393                  // above checkPermission call to always succeed!
 1394:                 warningString = AccessController.doPrivileged(
 1395                        new GetPropertyAction("awt.appletWarning",
 1396                                              "Java Applet Window"));

况且所有使用到 warningString 的外部代码都是通过 get 和 set 方法实现的,java 真该把它改为 private。

不过还好,看了本地化代码,C++的,就没有这个问题

private:
    //some other codes
    WCHAR * warningString;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值