初识Java 1-1 面向对象的语言

目录

引用的作用

数据的储存

常见的数据储存方式

特殊储存的基本类型

数组

销毁对象

基本类型的作用域

对象的作用域

创建新类型 - class关键字

方法、参数和返回值

参数列表

编写程序

名称可见性

使用组件

static关键字

Java程序

编程风格(驼峰式命名法)


 

本笔记参考自: 《On Java 中文版》


        不同于C++的向后兼容,Java的设计预期就是编写面向对象的程序。因此,在进行程序的编写之前,我们需要先熟悉面向对象的知识。

引用的作用

        在编程中,我们往往需要通过内存来处理各种元素,比如C/C++使用指针进行间接的内存操作。而Java将一切视为对象,通过对象来进行内存的操作。虽然如此,但在实际操作中,我们会使用到的其实是该对象的引用

        例如,如果我们想要储存一句话,我们就会需要使用到一个String类型的引用:

String s;

        上述的语句并没有创建一个对象,而是创建了一个引用。此时还不能向 s 发送信息,因为这个引用还没有连接任何对象。比较安全的做法是在创建引用时对其进行初始化:

String s = "初始化的内容";

        这就是引用的作用:关联对象。另外,上述这种初始化的方式(使用带引号的文本)是String类独有的,创建、初始化对象更常用的方式是使用new关键字:

String s = new String("初始化的内容");

    除去Java的预置类型,我们也可以手动进行新类型的创建。

数据的储存

常见的数据储存方式

数据储存方式 特点
寄存器 速度最快的数据储存方式,将数据直接保存在中央处理器中。(在Java中,寄存器无法由程序员进行分配)
效率仅次于寄存器。不过Java要求明确所以栈上对象的生命周期,这在一定程度上限制了其的灵活性。多用于存放对象引用
用于存放所有的Java对象。编译器不关心堆上的对象的生命周期,所以堆的使用更为灵活。
常量存储 常量通常直接保存在程序代码中,它们的值不会改变。(有时常量会与代码分开保存,此时常量可以保存在只读存储器中)
非RAM存储 这种数据不保存在应用程序中,它们的生命周期不依赖于应用程序。通常,这种数据被保存在其他媒介中。

特殊储存的基本类型

        new关键字是在堆上创建对象,在面对一些简单的变量时,这种做法就显得不够高效。Java的做法是创建“自动变量”,这种变量会直接储存在栈上面,运行效率较高。

    Java定义了每一种基本类型占用的空间大小,这种规定的一致性也给予了Java更好的可移植性。

        当然,如果遇到要在堆上开辟基本类型对象的情况,Java也提供了对应的“包装类”。通过包装类,可以把基本类型转变为位于堆上的非原始对象:

// 将基本类型转变为对应的包装类对象
char c = 'x';
Cahracter ch = new Character(c);

// 直接使用包装类进行初始化
Character ch = new Character('x');

// Java的“自动装箱”机制,能够将基本类型自动转换为包装类对象
Character ch = 'x';

        反过来,将对象转变为基本类型也是可以的:

char c = ch;

    Java提供了两个类来支持高精度计算,分别是BigIntegerBigDecimal。这两个类都没有对应的基本类型。


数组

        和许多的编程语言一样,Java也支持数组。但不同于C和C++中数组就是内存块的概念,Java对数组的要求更加严格,也更加安全。在Java中,数组有以下特征:

  1. 一定被初始化;
  2. 无法访问数组边界之外的元素。

    这使得Java的数组拥有更大的代价,但从安全性等角度来看,这是值得的。

        和之前提到的概念相吻合,Java的数组实际上还是存放着引用。Java会将这些引用初始化成特殊值:null,以防止某些数组问题的出现。(如果一个数组用来被放置基本类型,那么这些元素的初识值将会是0)
 

销毁对象

        在C和C++中,对象需要手动销毁,由程序员来回收内存,这会导致一些难以发觉的问题。而Java对内存的自动释放也在这一层面上帮助程序员分担了压力。

基本类型的作用域

||| 作用域的概念:作用域会决定其范围内定义的变量名的可见性和生命周期。

        Java通过大括号({ })来定义作用域的范围,如下所示:

{
    int a = 12;    
    // 此时只有变量a是存在并且可以使用的
    {
        int b = 100;    
        // 此时a、b都存在
    }
    // 此时超出了b的作用域,只有a存在
}

        但值得注意的是,Java不会运行在外围数据域中“隐藏”变量,这被认为是会引发歧义的:

{
    int x = 10;
    {
        int x = 20;    // 出现语法错误
    }
}

对象的作用域

        与基本类型不同,在Java中,若使用new关键字进行对象的创建,该对象在作用域结束后仍会存在(但是作为连接的引用却会消失):

{
    String s = new String("内容");
}// 作用域结束,s被销毁

        当作用域结束时,引用s会被销毁,但其连接的对象仍会占用一块内存。此时已经无法再次使用这一占用内存的对象,因为唯一的引用s已经离开了它的作用域。这一情况如果发生在C和C++中,无疑是令人头疼的。但Java会通过自带的垃圾收集器监视所有对象,并及时销毁无用对象。这就解决了“内存泄漏”这一严重的编程问题。


创建新类型 - class关键字

        大多数的面向对象编程语言会使用“class”关键字来描述新类型,其用法如下:

class AtypeName{
    // 类的具体实现
}

        在创建了一个新类型后,我们就可以通过new关键字创建一个该类的对象:

AtypeName a = new AtypeName();

        当然,上述的类还缺少很多东西,这些都需要程序员进行补齐。一个类可以有两种元素,分别为:字段(数据成员)和方法(成员函数)。我们使用引用,就是与其中的字段进行互动。

    也有一些字段是某一对象的引用,此时也需要使用new关键字对这一引用进行初始化。

        一般来说,对象都会单独保存其字段,不同对象的字段之间不会共享:

class DataOnly{
    int i;
    double d;
    boolean b;
}

        上述代码定义的类只有数据字段,当我们为这一类创建了一个对象后,就可以通过对象成员为字段赋值(引用与字段之间使用“.”进行连接):

//创建对象
DataOnly data = new DataOnly();

//通过对象的引用名进行字段赋值
data.i = 10;
data.d = 1.1;
data.b = false;

类中的默认值

        若一个类的某一字段是基本类型,那么这一字段就会默认被初始化(这一机制只适用于当变量作为类的成员存在时)。这种默认值不一定合理,所以最好的方式还是显式地初始化。

    除此之外,局部变量并不会被这样初始化,此时需要程序员为其赋值。若没有进行赋值,Java就会进行报错。

方法、参数和返回值

        在C和C++中,“函数”用于表示子程序。但Java没有这一概念,取而代之的是“方法”,即“做某件事的方式”。方法有四个最基础的部分:方法名、参数、返回值和方法体,例如:

ReturnType methodName(/* 参数列表 */){
    // 方法体
}

其中:

  • 返回值:表示当调用该方法时,该方法生成的值是什么类型;
  • 参数列表:提供需要传递给方法的信息(类型和名称);
  • 方法名和参数列表共同构成了“方法签名”(该方法的唯一标识符)。

    在Java中,方法只能作为类的一部分存在,且只能通过对象进行调用。

        调用对象方法和调用字段类似,都是通过“.”进行,不同的是调用方法时还需要写明参数列表:

objectReference.methodName(arg1, arg2, arg3);

参数列表

        参数列表负责描述传递给方法的信息,和Java的其他部分一样,这些被传递的信息也是对象。因此,在进行传参的时候,也会需要描述这些对象的类型和对象名。因为实际被操作的是对象的引用,所以引用的类型就必须正确——传入的对象类型必须与方法定义的参数类型一致。

int f(String s){
    return s.length * 2;
}

        return关键字使方法结束,并且将方法产生的值进行返回,该值的类型也必须与返回值的类型相一致。

编写程序

名称可见性

        为了方便区分不同模块的相同名称,C++引入了命名空间的概念。而Java则另辟蹊径,设计者将互联网域名反转使用(域名是唯一的),以此保证冲突不会发生。举个例子:若域名是xxx.com,那么abc库的名称就是com.xxx.utility.abc。其中的“.”用来分隔域名(其中,utility指Java的实用工具包)。

    通过上述的这种方式,Java为文件中的每一个类生成了唯一对应的标识符,而由于一些历史原因,包名都是小写字母。

        通过关联命名空间和反转的URL生成文件路径存在一个缺点,那就是冗长的文件夹路径。还是上面的例子:若我需要使用com.xxx.utility.abc这一命名空间,我就需要创建com和xxx的空文件夹。在一些更大的工程中,这些路径也被用于保存一些表明文件夹内容的数据,而为了管理这些套娃式的代码,使用好的IDE是一个不错的选择。


使用组件

        编译器无法自动找到存放在其他文件中的类,最简单的理由是一个类可能存在许多不同的定义。为此,就需要使用import关键字:import关键字的作用就是通知编译器导入一个指定位置的包(即放置了各种类的库)。

        若使用的是编译器自带的各种Java标准库组件,就不需要考虑那些冗长的域名,而可以这样直接使用:

import java.util.ArrayList;    //使用位于util库的ArrayList类

        或者使用通配符“*”引入util库中的所有类:

import java.util.*;

    但每一个被用到的类最好应该被单独引入。


static关键字

        若我们需要使用一个对象,一般需要先使用new关键字为对象分配内存,然后才能使用其的方法。但这并没有办法很好地处理下面两种情况:

  1. 需要通过一块共享空间保存特定字段;
  2. 即便没有生成对应的对象,也希望可以使用其中的某些方法。

        为此,Java使用了static关键字,带有static的方法或者字段不会依赖于任何对象(当然,我们无法通过static对象调用非static成员或方法)。这些只服务于类的数据或方法也被称为“类数据”和“类方法”。创建并初始化一个static字段的例子如下:

class StaticTest{
    static int i = 0;
}

        就算存在两个StaticTest的对象,StaticTest.i也只会占据一块内存空间。这意味着字段i会被两个对象共享

        通过类名和引用名都可以调用static成员,例如:

//使用类名进行static字段的调用
StaticTest.i++;

//使用引用名进行static字段的调用
StaticTest t = new StaticTest();
t.i++;

    一般更推荐使用类名调用static方法。

        同理,也可以这样调用static方法,例如:

class Test {
    static void f() {
        StaticTest.i++;
    }
}

//通过类名调用static方法
Test.f();

        static关键字的使用会改变数据生成的方式:static字段基于类进行创建,而非static字段是基于对象创建的。

Java程序

        这是一个完整的Java程序,该程序打印了一串字符串,和通过Java标准库的Date类生成的日期:

import java.util.*;                //使用import引入额外的类

public class HelloWorld {
    public static void main(String[] args) {
        System.out.printf("Hello world, it's: ");    //打印字符串
        System.out.println(new Date());              //打印Date类生成的日期
    }
}

    其中的out字段就是一个static PrintStream对象,因此它无需创建就可以直接使用。

        该代码的生成结果如下:

        每一个Java文件都会自动导入一个特定的库,即java.lang。而除此之外的类,就需要使用import关键字进行引入。上述程序中使用到的Date类就存在于util库中,因此我们需要在程序的开头进行util库的引入。

        注意:文件中必须要有一个与该文件同名的类。若这个文件是一个可以单独运行的文件,与文件同名的类中还需要有一个入口方法main(),其格式和返回值如下:

public static void main(String[] args) { //...

其中,public关键字表示该方法可以被外部程序所调用。main()的参数是一个String对象的数组,args参数是被要求强制传递的。

编译和运行

        若需要编译之前编写的程序(HelloWorld.java),首先需要打开该程序所在的目录,然后通过命令行输入:

javac HelloWorld.java

        若编译没有报错,则会生成一个HelloWorld.class文件,此时可以继续输入:

java HelloWorld

        通过这行命令就可以将程序的结果输出到控制台了。

编程风格(驼峰式命名法)

        “驼峰式命名法”要求:

  1. 类名:首字母要大写,若是类名包含多个词,则汇总所有词,并且每一个词的首字母都要大写,例如:
    class AllTheColorOfTheRainbow{ //...
  2. 其他内容(方法、字段和对象名等):首字母小写,其他的地方和类名一样,例如:
    class AllTheColorOfTheRainbow{ 
        int anTnterRepresentingColors;
        void changeTheHueOfTheColor(int newHue) {
            //...
        }
        //...
    }

你可能感兴趣的:(Java,java)