Think in Java 第四章

控制执行流程

测试while

public class whileTest {
static boolean condition(){
boolean result = Math.random() < 0.99;
System.out.println(result + ",");
return result;
} public static void main(String[] args) {
while (condition())
System.out.println("Inside 'while'");
System.out.println("Exited 'while'");
}
}
===============================================
true,
Inside 'while'
true,
Inside 'while'
true,
Inside 'while'
true,
Inside 'while'
false,
Exited 'while'

Math.random 随机生产 0 ---1 的数字

do - while 至少执行一次

for循环常用于计数任务

public class whileTest {
public static void main(String[] args) {
Random rand1 = new Random();
Random rand2 = new Random();
for(int i = 0; i < 5; i++) {
int x = rand1.nextInt();
int y = rand2.nextInt();
if(x < y) System.out.println(x + " < " + y);
else if(x > y) System.out.println(x + " > " + y);
else System.out.println(x + " = " + y);
}
Random rand3 = new Random();
Random rand4 = new Random();
for(int i = 0; i < 5; i++) {
int x = rand3.nextInt(10);
int y = rand4.nextInt(10);
if(x < y) System.out.println(x + " < " + y);
else if(x > y) System.out.println(x + " > " + y);
else System.out.println(x + " = " + y);
}
} }
==================================================== -1636716208 < -1366578013
-630773338 > -1420580444
342336183 < 784053746
1142887002 > 325688001
-1102830792 > -1683393166
8 > 4
3 > 0
7 < 8
0 < 3
1 < 6

forseach

不必创建 int 变量 去对由其访问项构成的序列 进行计数

for (int i : range(10))
print(i+"");
===============
0 1 2 3 4 5 6 7 8 9

练习8

public class SwitchTest {
public static void main(String[] args) {
for(int i = 0; i < 11; i++) {
switch(i) {
case 0: print("zero"); break;
case 1: print("isa"); break;
case 2: print("dalawa"); break;
case 3: print("tatlo"); break;
case 4: print("apat"); break;
case 5: print("lima"); break;
case 6: print("anim"); break;
case 7: print("pito"); break;
case 8: print("walo"); break;
case 9: print("siyam"); break;
default: print("default");
}
}
}
}
======================================================
zero
isa
dalawa
isa
dalawa
dalawa
tatlo
apat
lima
anim
pito
walo
siyam

练习9

public class Fibonacci {
int fib(int n) {
if(n < 2) return 1;
return (fib(n - 2) + fib(n - 1));
}
public static void main(String[] args) {
Fibonacci f = new Fibonacci();
int k = Integer.parseInt(args[0]);
System.out.println("First " + k + " Fibonacci number(s): ");
for(int i = 0; i < k; i++)
System.out.println(f.fib(i));
}
}
==================================================
1
1
2
3

第五章

初始化与清理

构造器 和 垃圾回收机制

5.1 用构造器 确保初始化

​ 可以假想为每一个类都定义了 initialize() 方法。通过构造器,确保每个类都被初始化了。创建对象时,如果其类具有构造器,Java就会在用户操作之前自动调用相应的构造器,从而保证了初始化。

构造器 与 类 同名, 方便计算机自动找到,而且不与自定义的属性或者方法重名。

构造器

  • 名称与类名完全相同,方法名的首字母 小写,不适用于构造器
  • 没有参数的构造器,叫无参构造 或者 默认构造
  • 有形式参数的构造器叫有参构造,以便指向如何创建对象(Tree 类有一个构造器,接受整形变量来表示数的高度,创建Tree对象的时候,就形成了一个有高度的Tree)
  • 有助于 减少错误,代码容易阅读

练习1

lass Tester {
String s;
} public class ConstructorTest {
public static void main(String[] args) {
Tester t = new Tester();
System.out.println(t.s);
}
}
=============================================
null

练习2

class Tester2{
String s1;
String s2 = "hello";
String s3 = "initialization by self";
Tester2(){
s3 = "constructor initialization";
}
}
public class ConstructorTest {
public static void main(String[] args) {
Tester2 t2 = new Tester2();
System.out.println("t2.s1="+ t2.s1);
System.out.println("t2.s2="+ t2.s2);
System.out.println("t2.s3="+ t2.s3);
}
}
=================================================
t2.s1=null
t2.s2=hello
t2.s3=constructor initnizetion

构造器初始化优先级高

5.2 方法重载

名字

  • 创建一个对象时,给对对象分配的存储空间取了一个名字

  • 方法则是给某个动作取个名字

  • 通过名字引用所有的对象和方法。

  • 每一个方法都要有唯一的名称

    ​ 假设你要创建一个类,既可以用标准方法初始化,也可以从文件里读取信息来初始化,这就需要两个构造器:一个默认构造器,一个取字符串作为形式参数----该字符串表示初始化方法对象所需要的文件名称。急类名。为了让方法名相同而形式参数不同的方法同时存在,必须用到方法的重载

5.2.1 区分方法的重载

区分方法的重载 其实很简单,

  • 每个重载的方法都必须有第一无二的参数列表。

  • 参数的顺序也可以把他们区分开来

5.3 默认构造方法

没有形式参数,创建一个“默认对象”。如果你写的类中没有构造器,则编译器会自动帮你创建一个默认构造方法。

练习3

class Kabayo{
Kabayo(){
System.out.println(" is a Constructor");
}
} public class DefaultConstructorTest {
public static void main(String[] args) {
Kabayo k = new Kabayo();
}
}
======================================
is a Constructor

5.4 This 关键字

如果 只有 一个 Peel 方法,创建了一个对象 a,一个对象 b.

a.peel(1);

b.peel(2);

它是被a调用了 还是 b呢?

编译器 暗自中 把 所操作对象的引用 作为 参数传递给 peel() 内部表示形式

peel(a,1);

peel(b,1);

在方法内部获得对当前对象的引用, 当前对象 : 调用这个方法的对象。 this

this 值调用方法的那个对象的引用 a b

  • 当你 在 方法中 调用 同一个类的其他方法 直接调用就好
  • 当你在方法中使用了 this 会应用到同一类的其他方法
  • 当需要返回当前对象的引用时,常常用 return 返回this
public class leaf {
int i =0;
leaf increment(){
i++;
return this;
}
void print(){
System.out.println("i = " +i);
} public static void main(String[] args) {
leaf x = new leaf();
x.increment().increment().increment().print();
}
}
==========================================================
3

由于 increment()通过this 关键字返回了对当前对象的引用,所以很容易在一条语句里对同一个对象执行多次操作。

  • this 关键字 对于将当前方法传递给其他方法也很有用

练习8

public class Doc {
public static void main(String[] args) {
new Doc1().intubate();
}
}
class Doc1{
void intubate() {
System.out.println("prepare patient");
laryngoscopy();
this.laryngoscopy();
}
void laryngoscopy() {
System.out.println("use laryngoscope");
} }
===================================================
prepare patient
use laryngoscope
use laryngoscope

5.4.1 在构造器中调用构造器

一个类中写了多个构造器,有时可能想在一个构造器中调用另一个构造器,避免代码重复 可以用this

  • This 表示 这个对象 或者 当前对象,而它本身代表当前地下的引用。

  • this 添加了参数列表,对符合此参数列表的某个构造器的明确调用

    • 只能调用一个 不能调用两个
    • 编译器 禁止在其他方法里面 调用 构造器

5.4.2 static的含义

static 就是没有 this的 方法

  • 在 static 方法中 不能调用非静态方法,反过来可以。
  • 在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。
  • 全局方法。

5.5 清理 :终极处理 和 垃圾回收

  • 垃圾 回收 只知道释放哪些经由 new分配的内存

  • 为了释放 那些 不由 new 分配的内存,允许在 类中定义 finalize()方法。

    finalize

    1. 垃圾回收 启动 (准备回收对象占用的内存)
    2. 调用 finalize ()方 法 做一些重要的清理工作
    3. 真正回收 内存。
    4. 有趣的用法 终结 条件的验证

无论对象时如何创建的 ,垃圾回收器都会负责释放对象所占据的所有内存。所以 finalize之所以要用 ,是因为在分配内存时候可能用到了 本地方法 的情况 本地方法目前只支持 c 和 c++

也许调用了 c 的 malloc()函数 系列 来分配存储空间。而且除非用 free()函数 来释放 空间 否则 得不到释放

如果JVM 虚拟机 并未 面临内存耗尽的情况 是不会浪费实际去执行 垃圾回收 回复内存的

练习10

class WebBank{
boolean loggedIn = false;
WebBank(boolean logStatus){
loggedIn = logStatus;
}
void logIn(){
loggedIn = true;
}
void logOut(){
loggedIn = false;
}
protected void finalize(){
if (loggedIn)
System.out.println("Error : still logged in");
}
}
public class TerminationConditionEx {
public static void main(String[] args) {
WebBank bank2 = new WebBank(true); // 定义出来不用 垃圾回收自动清理
bank1.logOut();
new WebBank(true); // 一直new 一个 对象 ,一直得不到清理。调用 fianlize方法 检查 验证终结条件
System.gc(); }
} ==========================================================
Error : still logged in

练习11

class Webbank {
boolean loggedIn = false;
Webbank(boolean logStatus) {
loggedIn = logStatus;
}
void logOut() {
loggedIn = false;
}
protected void finalize() {
if(loggedIn)
System.out.println("Error: still logged in");
// Normally, you'll also call the base-class version:
// super.finalize();
}
}
public class BankTest {
public static void main(String[] args) {
Webbank bank1 = new Webbank(true);
Webbank bank2 = new Webbank(true);//垃圾回收自动清除
new Webbank(true); // 添加未被处理对象
// Proper cleanup: log out of bank1 before going home:
bank1.logOut(); // bank1 对象 被清理
// Forget to logout of bank2 and unnamed new bank
// Attempts to finalize any missed banks:
System.out.println("Try 1: ");
System.runFinalization();
System.out.println("Try 2: ");
Runtime.getRuntime().runFinalization();
System.out.println("Try 3: ");
System.gc();
System.out.println("Try 4: ");
// using deprecated since 1.1 method:
System.runFinalizersOnExit(true);
}
} =======================================================================

练习12

class Tank{
int howFull = 0;
Tank(){this(0);}
Tank(int fullness){
howFull = fullness;
}
void sayHowFull(){
if(howFull == 0) System.out.println("Tank is empty");
else System.out.println("Tank filling status =" + howFull);
}
void empy(){
howFull = 0;
}
protected void finalize(){
if(howFull == 0)
System.out.println("Error:Tank is empty");
} } public class TankTest {
public static void main(String[] args) {
Tank tank1 = new Tank();
Tank tank2 = new Tank(3);
Tank tank3 = new Tank(5); tank2.empy(); new Tank(6);
System.out.println("Check tanks:");
System.out.println("tank1:");
tank1.sayHowFull();
System.out.println("tank2:");
tank2.sayHowFull();
System.out.println("tank3:");
tank3.sayHowFull();
System.out.println("first forced gc():");
System.gc();
System.out.println("try deprecated runFinalizersOnExit(true):");
System.runFinalizersOnExit(true);
System.out.println("last force gc():");
System.gc();
}
}
Check tanks:
tank1:
Tank is empty
tank2:
Tank is empty
tank3:
Tank filling status =5
first forced gc():
try deprecated runFinalizersOnExit(true):
last force gc():
Error:Tank is empty
Error:Tank is empty

5.5.4 垃圾回收是如何工作

垃圾回收对与提高对象的创建速度有明显的效果。 存储空间的释放竟然会影响存储空间的分配

Java中 堆的实现 像一个传送带,每分配一个内存,它就前进一格。 对象在存储空间的分配速度非常快。Java的堆指针只是简单的移动到尚未分配的区域。但不是单纯的像传送带一样,垃圾回收的介入,在分配内存的同时,也释放前面已经分配好的内存,堆指针可以指向释放的区域,使得对象紧凑排列。

  • 引用计数法。常用来说明垃圾收集的工作方式,但似乎从未被应用于任何一种JVM中
  • 对 任何 “活”,一定能最终追溯到其存活在堆栈或者静态存储区之中的引用。

如何找到活着的对象(不同的Java虚拟机 实现不同)

  • 停止--复制 (不属于后台回收模式)停止程序 将所有存活的对象从当前堆复制到另一个堆,没有完全复制的都是垃圾。当对象复制到新堆的时候是 一个挨着一个

    • 引用必须被修正 (位于 堆 或 静态存储区的引用可以被直接修改)
    • 必须有两个堆 JVM 从堆中按需要 分配几个大堆 复制动作发生在大堆之间
    • 当产生少了垃圾 或者 没有垃圾的时候,一味的复制 会浪费很大的效率
      • 为了避免: JVM 会进行检查:没有新垃圾产生或者少量,切换到另一种模式(标记 -- 清除)
  • 标记--清除 思路也是 : 从堆栈 或者 静态存储区域出发,遍历所有引用,进而找出存活的对象。
    • 步骤

      • 每当找到一个活得对象,就会给对象一个标记,这个过程不会回收任何对象
      • 标记工作全部完成后,清理没有被标记的对象。空间是不连续的 ,重新整理剩下的对象。
  • 自适应
    • JVM , 内存 分配以较大的块为单位。 每个块都有相应的 代数(generation count) 来记录 是否存活,通常 块在某处被引用,代数增加

      • 大型对象单独占一个块。 不会被 复制 只是 代数增加
      • 小型对象 会被 复制 并整合
    • JVM 会 监视
      • 所有的 块 都稳定,但是垃圾回收效率 很低 切换到 标记 -- 清楚 方式
      • 堆中空间出现 很多碎片, 切换到 停止--复制

JVM 有 许多 附加技术 用来 提升速度

  • 类加载器 有关 的

    • Just in time 即时 把 程序 全部 或者 部分 翻译成 本地机器码(JVM 工作),程序运行速度会得到提高。

例子

​ 当 加载 一个 类库时候(通常时该类创建第一个对象),编译器会找到 .class文件,然后将该类的 字节码 装入内存。

两种方案:

  • 即时编译器 编译所有代码

    • 降低程序速度
  • 惰性评估 (lazy evaluation)
    • 即时 编译器 只在需要的时候 编译代码 不会被执行的代码 压根不会 被编译。
    • 代码每次 被执行的时候都会做一些 优化 执行的次数 越多 速度越快。

成员初始化

Java 尽力 保证: 所有的 成员变量在使用前都能得到恰当的初始化。对于方法的局部变量,Java以编译时的错误来贯彻这种保证

  • 基本数据 类型 成员 保证都会有一个初始值

5.6.1 指定初始化

5.7 构造器 初始化

可以用 构造 来初始化。 无法阻止 自动 初始化 的 进行,他将在构造器被调用之前发生

5 .7.1 初始化 顺序

变量 定义的先后顺序 决定了 初始化的先后顺序。即使变量定义散步于方法定义之间,他们仍然会在任何方法(包括构造器)被调用之前得到初始化。

5.7.2 静态数据的初始化

​ 无论建立多少个对象,静态数据都只占一份 存储区域。static 不能应用与局部变量,因此它只能作用 于

  • 静态的基本域 没有进行初始化 , 获得基本类型的标准初值
  • 一个对象的引用,默认值就是null
  • 静态初始化 只有在 必要时刻才会 进行,如果 在类中定义了静态 或者类中的方法定义了静态,那么在没有调用这个类(生成类的对象) 或者方位类的静态成员 那么 不会被初始化,如果 调用了这个类 (创建 类 对象 或者 类的精要方法 静态域 首次被访问)
    • Java解释器必须查找到类路径定位到 类.class文件。
    • 然后载入 class 有关静态初始化的所有操作都会被执行,(因此,静态初始化只在 class对象首次加载的时候进行一次)
    • 当new一个对象的时候,首先会在堆上为这个 对象 分配足够的存储空间
    • 保证这个 空间事清零的 自动的将 类中的所有基本类型 都设置成默认值,数字 字符 布尔是 0 引用为null
    • 执行所有字段定义处的初始化动作
    • 执行构造器。
  • 静态变量 被 初始化 过后 再 重复调用 不会 被出被再次初始化

5.7.3 显式的静态初始化

Java 允许 将多个静态初始化 组织 成 一个 “静态块”


这段代码仅执行一次 :当首次生成 这个类的 一个对象时,或者首次访问 属于那个类的静态数据 成员时

练习 14

class Go {
static String s1 = "run";
static String s2, s3;
static {
s2 = "drive car";
s3 = "fly plane";
System.out.println("s2 & s3 initialized");
}
static void how() {
System.out.println(s1 + " or " + s2 + " or " + s3);
}
Go() {
System.out.println("Go()"); }
} public class ExplicitStaticEx {
public static void main(String[] args) {
System.out.println(g1.s1);
System.out.println("Inside main()");
Go.how();
System.out.println("Go.s1: " + Go.s1);
}
static Go g1 = new Go();
static Go g2 = new Go();
}
================================================
s2 & s3 initialized
Go()
Go()
run
Inside main()
run or drive car or fly plane
Go.s1: run

5.7.4 非静态实例化

Java 中也有 实例初始化 的类似语法, 用来初始化每个对象的非静态变量。

练习 15

class Test {
String s;
{
s = "Initializing string in Tester";
System.out.println(s);
}
Test() {
System.out.println("Tester()");
}
} public class InstanceClauseTest {
public static void main(String[] args) {
new Test();
}
}
====================================================
Initializing string in Tester
Tester()

5.8 数组初始化

int[] a

定义的时候 初始化

int[] a = new int[rand.nextInt(20)]

a[i] = rand.nextInt(500);

也可以用花括号括起来 的 列表 来 初始化 对象数组。 有两种形式

Integer[] a = {

	new Integer(1),

	new Integer(2),

	3,  // autoboxing自动封装

}
Integer[] b = new Integer[]{

	new Integer(1),
new Integer(2),
3, //autoboxing
}

创建一个引用数组, 创建一个对象 并把对象赋值给引用 才算初始化进程结束

练习16

public class StringArrays {

        public static void main(String[] args) {
String[] s = { "one", "two", "three", };
for(int i = 0; i < s.length; i++)
System.out.println("s[" + i + "] = " + s[i]);
}
}

练习17

class InitTest {
InitTest(String s) {
System.out.println("InitTest()");
System.out.println(s);
}
} public class InitTest17 {
public static void main(String[] args) {
InitTest[] it = new InitTest[10];
}
}

什么都没打印


练习18

class InitTest {
InitTest(String s) {
System.out.println("InitTest()");
System.out.println(s);
}
} public class InitTest18 {
public static void main(String[] args) {
InitTest[] it = new InitTest[5];
for(int i = 0; i < it.length; i++)
it[i] = new InitTest(Integer.toString(i));
}
}
===========================================================
InitTest()
0
InitTest()
1
InitTest()
2
InitTest()
3
InitTest()
4

5.8.1 可变参数列表

可以 应用于 参数个数 或者 类型 未知 的 场合。

由于所有的类都直接或者间接继承object类,所以可以 创建 以 object 数组 为参数的方法。

**有了 可变参数 编译器 就再也不哟个 显示的编写 数组 语法了,当你 指定参数时,编译器 实际上会为你填充参数 如果你有了 一组事物 你可以把他们当作列表传递 而如果你已经有了一个数组 该方法可以把它们当作 可变参数列表传递 **

当有 可选的 尾随(trailing) 参数 这一方法 就会很好用

可变参数 列表为 数组的情况 如果没有 元素 数组尺寸为 0

可变参数 列表 可以 于 自动包装机制 和谐相处

可变参数列表 使 重载 变得 复杂了

每种情况下,编译器都会自动包装机制来匹配重载方法,然后匹配最明确的方法

在不使用 参数调用 f() 时 编译器 就不知道 调用那个方法了

可以 增加一个非 可变参数来 解决


练习19

public class InitTest19 {
static void showStrings(String... args) {
for(String s : args)
System.out.print(s + " ");
System.out.println();
}
public static void main(String[] args) {
showStrings("one", "TWO", "three", "four");
showStrings(new String[]{"1", "2", "3", "4"});
}
}
===========================================================
one TWO three four
1 2 3 4

练习 20

public class VarargEx20 {
public static void main(String... args) {
for(String s : args)
System.out.print(s + " ");
System.out.println();
}
}

5.9 枚举类型

enum 关键字

enum 可以和 switch 组合

练习 21

public class EnumEx21 {
public enum Bills {
ONE, FIVE, TEN, TWENTY, FIFTY, HUNDRED
}
public static void main(String[] args) {
for(Bills b : Bills.values())
System.out.println(b + ", ordinal " + b.ordinal());
}
}
===================================================================
ONE, ordinal 0
FIVE, ordinal 1
TEN, ordinal 2
TWENTY, ordinal 3
FIFTY, ordinal 4
HUNDRED, ordinal 5

练习 21

enum Bills {
ONE, FIVE, TEN, TWENTY, FIFTY, HUNDRED
}
public class Wallet {
Bills b;
public static void main(String[] args) {
for(Bills b : Bills.values()) {
System.out.print("Worth: ");
switch(b) {
case ONE: System.out.println("$1"); break;
case FIVE: System.out.println("$5"); break;
case TEN: System.out.println("$10"); break;
case TWENTY: System.out.println("$20"); break;
case FIFTY: System.out.println("$50"); break;
case HUNDRED: System.out.println("$100"); break;
default: break;
}
}
}
}
=====================================================================
Worth: $1
Worth: $5
Worth: $10
Worth: $20
Worth: $50
Worth: $100

Think in Java 第四 五 章的更多相关文章

  1. Java核心技术第五章——1.类、超类、子类(2)

    继上一篇Java核心技术第五章——1.类.超类.子类(1) 6.重载解析 假如调用ClassName.Method(args) 1.编译器列出类ClassName所有名为Method的方法. 2.编译 ...

  2. “全栈2019”Java多线程第五章:线程睡眠sleep()方法详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  3. “全栈2019”Java异常第五章:一定会被执行的finally代码块

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  4. “全栈2019”Java第九十五章:方法中可以定义静态局部内部类吗?

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  5. “全栈2019”Java第四十七章:继承与方法

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  6. “全栈2019”Java第十五章:Unicode与转义字符

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  7. “全栈2019”Java第四十三章:封装

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  8. “全栈2019”Java第二十五章:流程控制语句中循环语句while

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  9. JAVA基础第五章-集合框架Map篇

    业内经常说的一句话是不要重复造轮子,但是有时候,只有自己造一个轮子了,才会深刻明白什么样的轮子适合山路,什么样的轮子适合平地! 我将会持续更新java基础知识,欢迎关注. 往期章节: JAVA基础第一 ...

随机推荐

  1. Github不为人知的一个功能,一个小彩蛋

    Github 是一个基于Git的代码托管平台,相信很多人都用过,当然这些"很多人"中大部分都是程序员.当你在Github上创建仓库时(Github称项目为仓库),你会给这个仓库添加 ...

  2. 基础篇:JAVA原子组件和同步组件

    前言 在使用多线程并发编程的时,经常会遇到对共享变量修改操作.此时我们可以选择ConcurrentHashMap,ConcurrentLinkedQueue来进行安全地存储数据.但如果单单是涉及状态的 ...

  3. asp.net core 5.0 中的 JsonConsole

    asp.net core 5.0 中的 JsonConsole Intro asp.net core 5.0 中日志新增了 JsonConsole,还是输出日志到 Console,但是会应用 Json ...

  4. maven项目pom.xml解析

  5. python后端开发面试总结

    网络协议 通信计算机双方必须共同遵从的一组约定,只有遵守这个约定,计算机之间才能相互通信交流 TCP / IP TCP/IP(传输控制协议/网际协议)是指能够在多个不同网络间实现信息传输的协议簇.TC ...

  6. ATM_tests

    ATM取款机练习程序 一.程序分析 自顶向下.逐步细化 按照程序执行的流程,将程序分解为若干个功能相对独立的函数(方法),每个函数(方法)负责某一功能,然后根据程序执行的流程,将函数(方法)组装(调用 ...

  7. ORA-39700: database must be opened with UPGRADE option【转】

    1. 错误 数据库升级后(从11.2.0.1升级到11.2.0.4)启动报错 SQL> startup ORACLE instance started.   Total System Globa ...

  8. FastApi 进阶

    前言 终于有了第一个使用 FastApi 编写的线上服务, 在开发的过程中还是遇到了些问题, 这里记录一下 正文 目录结构 我们知道, FastApi 的启动方式推荐使用 uvicorn, 其启动方式 ...

  9. python Logger模块单例模式

    前言 提前祝大家过个好年 最近忙于项目,今天抽出点时间写写Blog谈谈昨天遇到的问题 项目最近要收尾了,想把Logger规整一下,因为很多地方都有用到 Python的Logger模块是Python自带 ...

  10. 浅谈TypeScript,配置文件以及数据类型

    TypeScript在javaScript基础上多了一些拓展特性,多出来的是一些类型系统以及对ES6新特性的支持最终会编译成原始的javaScript, 文件名以.ts结尾,编译过后.js结尾,在an ...