Java核心技术(基础知识)笔记

本文详细介绍了Java编程的基础,涵盖面向对象设计、即时编译、基本程序设计结构、类与对象、继承、接口、内部类等多个核心主题。文章讨论了Java的特性,如字符串、数组、异常处理、泛型、集合框架、并发处理,并提供了丰富的示例和解释,旨在深入理解Java编程的核心概念和技术。
摘要由CSDN通过智能技术生成

第一章 Java程序设计概述

面向对象设计

用木匠打个比方,一个“面向对象的”木匠始终关注的是所制作的椅子,第二位才是所使用的工具;一个“非面向对象”的木匠首先考虑的是所用的工具。

即时编译

解释虚拟机指令肯定会比全速运行机器指令慢很多。然而,虚拟机有一个选项,可以将执行最频繁的字节码序列翻译成机器码,这一过程被称为即时编译。

字节码可以(在运行时刻)动态的翻译成对应运行这个应用的特定CPU机器码。

即时编译器还可以消除函数调用(即“内联”)。

第三章 Java的基本程序设计结构

一个简单的Java应用程序

根据Java语言规范,Java虚拟机将从指定类中的main方法开始执行。

不过,当main方法不是public时,有些版本的Java解释器也可以执行Java应用。这是因为Java虚拟机规范并没有要求main方法一定是public。这个问题已经得到了修复,在Java SE 1.4及以后的版本中强制main方法时public的。

整形

从Java 7开始,加上前缀0B或者0b就可以写二进制数。例如:0b1001就是9。同样,从Java 7开始,还可以为数字字面量加下划线,如用1_000_000表示一百万。

浮点类型

所有”非数值“的值都认为是不同的。

if (x == Double.NaN) // is never true

可以使用 Double.isNaN() 来判断(长得帅的肯定会戳进去看一下源码,很有意思哦)。

浮点数不适用于无法接受舍入误差的金融计算中。例如,

double result = 2.0 - 1.9; // result = 0.10000000000000009

这是因为二进制无法精确的表示 1/10。

可移植性是Java的设计目标之一。无论在哪个虚拟机上运行,同一运算应该得到同样的结果。对于浮点数的算术运算,实现这样的可移植性是相当困难的。double类型使用64位储存一个数值,而有些处理器使用80位浮点寄存器。这些寄存器增加了中间过程的计算精度。例如:

ddoble w = x * y / z;

使用严格浮点计算,截断中间数,可以了解一下 strictfp 关键字。

char类型

转义字符\u可以出现在加引号的字符常量或字符串之外(其他的转义字符不行)。例如:

public static void main(String\u005B\u005D args)

\u005B\u005D其实就是[],所以上面的代码就是程序的入口main函数。(可以编译成class文件并运行,但是不被IDE识别)

Unicode转义字符会在解析代码之前得到处理,举个吓死人的例子:

// file in c:\user

当你在代码里面加上这行注释的时候,点击运行按钮就会发现,编译过不了!!!我的理解是先会将文件里面的转义字符全部处理一下,当处理到这行注释的时候,发现了 \u 会当成转义字符来处理,但是 \u 后面的字符不合法,所以就报错了。

Unicode的基本平面,辅助平面,码点的概念,可以看维基百科。

一个字符可能有多个码点,一个char只能表示一个码点。

运算符

整数被0除将会产生一个异常,而浮点数被0除将会得到无穷大或者NaN结果。

数值类型之间的转换

两个操作数有一个是 double ,则两个数按照 double 处理,

否则,有一个是 float,则两个数按照 float 处理,

否则,有一个是 long,则两个数按照 long 处理,

否则,两个数按照 int 处理。

byte a = 1;
byte b = 2;
byte c = a + b; // error
byte a = 1;
a += 1; // ok,因为 += 会自动进行强制转换
位运算符

处理整形类型时,可以直接对组成整形数值的各个位完成操作,浮点数不行。

int a = 1;
a << 1; // ok
double b = 3;
b << 1; // error

位移运算符的右操作数要完成模32的运算(如果左操作是long型,则需要模64)。

1 << 35 相当于 1 << 3
字符串

编译器可以让字符串共享,只有字符串常量是共享的,+或者substring等操作产生的结果并不是共享的。

格式化输出:

使用参数索引来对一个参数进行多次格式化:

System.out.print("%1$s %2$tB %2$te %2$tY", "Due date:", new Date());

可以看到第二个索引对new Date()参数格式化了多次。使用<标志也可以达到同样的效果。

System.out.print("%s %tB %<te %<tY", "Due date:", new Date());
数组

Java中,允许数组长度为0,数组长度为0和null不同。

数组排序
Arrays.sort(a); // 这个方法使用了优化的快速排序算法

利用数组写一个抽彩游戏(这个算法还是很有想法的):

int[] numbers = new int[n];

for(int i=0; i<n; i++) {
   
    numbers[i] = i + 1;
}

int[] result = new int[k];
for (int i=0; i<k; i++) {
   
    int r = (int)(Math.random() * n);
    result[i] = numbers[r];
    // 最关键的代码,将上面随机出来的数用最后一个数覆盖
    numbers[r] = numbers[n - 1];
    // 将 n 减一,相当于去掉最后一个数
    n--;
}

第四章 类与对象

面向对象程序设计概述

OOP将数据放在第一位,然后再考虑操作数据的算法。

对象

对象状态的改变必须通过调用方法实现,如果不经过方法调用就可以改变对象状态,只能说明封装性遭到了破坏。

类之间的关系

最常见的关系有:

  • 依赖(“use-a”)
  • 聚合(“has-a”)
  • 继承(“is-a”)
Java类库中的LocalDate类

将时间与日历分开是一种很好的面向对象设计。通常,最好使用不同的类表示不同的概念。

用户自定义类

在一个源文件中,只能有一个公有类,但可以有任意数目的非共有类。

第一眼看到这句话我是懵逼的,后来仔细看了代码,发现应该说的是非内部类。

// Main.java
public class Main{
   
    public class Inner{
   }
}

class Main2 {
   
    
}

上面的源文件是Ok的。但是把Main2改成public的就不行。

封装的优点

可以改变内部实现,除了该类的方法之外,不会影响其他代码。

更改器方法可以执行错误检查,然而直接对域进行赋值将不会进行这些处理。

静态常量

我们常使用的System类

public class System {
   
    ...
    public static final PrintStream out = ...;
}

我们知道 final 修饰的变量是不允许将别的值赋给它的,但是System类有这样的一个方法:

public static void setOut(PrintStream out) {
   ...}

它可以将System.out设置为不同的流,原因是setOut是一个本地方法,它可以绕过Java语言的存取控制机制。

方法参数

Java程序设计语言总是采用按值调用。有些程序员认为Java程序设计语言对对象采用的是引用调用,实际上,这种理解是不对的,下面给出例子:

public static void swap(Car a, Car b) {
   
    Car temp = a;
    a = b;
    b = temp;
}

如果Java对对象采用的是按照引用传递,那么这个方法应该够实现交换数据的效果,但是,并没有。参数被初始化为对象引用的拷贝。

初始化块

调用构造器的具体处理步骤:

  1. 所有数据域被初始化为默认值(0,false或null)。
  2. 按照在类声明中出现的顺序,依次执行所有域初始化语句和初始化块。
  3. 如果构造器第一行调用了第二个构造器,则执行第二个构造器主体。
  4. 执行这个构造器的主题。
public class Main {
   
    {
   
        a = 2;
    }
    private int a = 3;
    
    public int getA() {
   
        return a;
    }
}

// Main m = new Main(); 问,m.getA() 的值?
对象析构与 finalize 方法

在实际应用中,不要依赖使用 finalize 方法回收任何短缺的资源,这是因为很难知道这个方法什么时候才能够调用。

我一直觉得,final,finally,finalize有啥区别,这个问题很傻×,因为他们毛关系没有,区别从何谈起。问问 final 与 volitile的区别吧!!!

将类放入包中

假定有一个源文件开头有下列语句:

package com.aprz;

编译器在编译源文件的时候不检查目录结构,即使这个源文件没有在子目录 com/aprz 下,也可以进行编译。但是,最终的程序将无法运行。如果包与目录不匹配,虚拟机就找不到类。

包作用域

如果,把一个类文件放置在类路径的某处的 java/awt 子目录下,那么我们就可以访问 java.awt 包的内部了。非常危险!

从 1.2 版开始,JDK 的实现者修改了类加载器,明确禁止加载用户自定义的、包名以“java”开始的类!

类路径

javac编译器总是在当前的目录中查找文件,但Java虚拟机仅在类路径中有“.”目录的时候才查看当前目录。如果没有设置类路径,那也并不会产生什么问题,默认的类路径包含“.”目录。然而如果设置了类路径却忘记了包含“.”目录,则程序仍然可以通过编译,但不能运行。

下面看一个类路径示例:

/home/user/classdir:.:/home/user/archives/archive.jar

假定虚拟机要搜寻 com.horstmann.corejava.Employee类文件。它首先要查看储存在jre/lib和jre/lib/ext目录下的归档文件中所存放的系统类文件。显然,在那里找不到相应的类文件,然后再查看类路径。然后查找一下文件:

/home/user/classdir/com/horstmann/corejava/Employee.class
com/horstmann/corejava/Employee.class从当前目录开始
com/horstmann/corejava/Employee.class inside /home/user/archives/archive.jar

编译器定位文件要比虚拟机复杂得多。如果引用了一个类,而没有指出这个类所在的包,那么编译器将首先查找包含这个类的包,并询查所有的import指令,确定其中是否包含了被引用的类。例如,假定源文件包含指令:

import java.util.*;
import com.horstmann.corejava.*;

并且源代码引用了Employe类。**编译器将试图查找jva.lang.Employee (因为java lang包被默认入)、java.util.Employee、com.hostmann.corejava.Employee和当前包中的Employee。**对这个类路径的所有位置中所列出的每个类进行逐查看。 如果找到了一个以上的类,就会产生编译错误(因为类必须是唯一的, 而import语句的次序却无关紧要)。

编译器的任务不止这些,它还要查看源文件( Source files) 是否比类文件新。如果是这样的话,那么源文件就会自动地重新编译

在前面已经知道,仅可以导入其他包中的公有类。一个源文件只能包含一个公有类,并且文件名必须与公有类匹配。因此,编译器很容易定位公有类所在的源文件。当然,也可以从当前包中导入非公有类。这些类有可能定义在与类名不同的源文件中。如果从当前包中导入一个类,编译器就要搜索当前包中的所有源文件,以便确定哪个源文件定义了这个类

这一段很长,我只能说QQ的图片文字识别真的牛逼。

第五章 继承

类、超类和子类

前缀“超”与“子”来源于计算机科学和数学理论中的集合语言的术语。

覆盖方法

尽管子类对象有父类的私有域,但是却无法在子类中访问这个域。(这句话是我总结的,可能并不严谨)

有些人(包括我)认为super与this应用是类似的概念,实际上,这样比较并不太恰当。这是因为super不是一个对象的引用,不能将super赋给另一个对象变量,它只是一个只是编译器调用超类方法的特殊关键字。

动态绑定

虚拟机知道一个引用的对象类型,所以能够正确的调用相应的方法。

多态

在Java中,子类数组的引用可以转换成超类数组的引用,而不需要采用强制类型转换。例如:

public class A {
   }
public class B extends A {
   }

B[] bs = new B[8];
A[] as = bs;

但是这样会有一个问题,如下:

as[0] = new A(
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值