Java 基础知识

这是我听翁恺老师JAVA课程的笔记
之前在W3SCHOOL过了一下,前面一下变量循环之类的就跳过了,这里主要记一下和其他语言语法上,概念上不同的地方

二维数组

        //Declare an array
        int a[][] = new int[3][5];
        //Define an array
        int [][]b = {
                {1,2,3},
                {4,5}   //缺省自动补0
        };
        //Traverse an array
        for(int i=0;i<2;i++){
            for(int j=0;j<3;j++){
                System.out.println(b[i][j]);
            }
        }

字符类型

单个字符是种特殊的类型:char

  • 单引号表示字符字面量:'a','1'
  • JAVA使用Unicode来表示字符=>可以表达汉字等多种语言文字
  • 可以进行字符计算=>对Unicode编码进行操作
    • 加减法
    • 大小写换算
    • 比较大小
  • 逃逸字符/转义字符 Escape character
    • +字符表示无法打印出来的控制字符or特殊字符
    • 

包裹类型

  • 每种基础类型有一种与之相对应的包裹类型
基础类型 Primitive Type 包裹类型 Wrapper Type
boolean Boolean
char Character
int Integer
double Double
  • 包裹类型有什么用?
    • 和基础类型一样,定义变量
    • 提供一些方便实用的方法
      • INT 获得类型最大值WrapperType.MAX_VALUE
      • Character 判断/转换大小写
      • String 比较是否相等String.equals()

字符串

  • 定义字符串Sting s;

  • Sting是一个类,Sting的变量是对象的管理者,而为拥有者

    • 就像数组变量是数组的管理者而非拥有者一样=>用new创建一个新的对象,初始化后,再交给一个变量进行管理String s = new String("hello world");
  • 使用+进行字符串连接

    • 如果一边为字符串,另一边不是字符串,则会将另一边自动转化为字符串进行连接
  • 输入字符串

    • in.next()读入一个单词,单词标志是空格(包括空格,tab,换行)
    • in.nextLine()读入一整行
Scanner in = new Scanner(System.in);
String s;

s = in.nextLine(); //读入一行
System.out.println(s);

s = in.next(); //仅读入第一个单词
System.out.println(s);
  • 判断两个字符串变量相同还是内容相同
    • 内容相同,但是变量名称不同的两个变量=>person1 == person2 ?=>False=>因为==比较的是两个变量指向的是否为同一个对象
    • str1.equals(str2) ?=>比较两个字符串内容是否相同

字符串操作

操作 方法
比较是否相等 s1.equals(s2)
比较大小 s1.compareTo(s2)
获取长度 s1.length()
访问字符 s1.charAt(index)
子串 s1.substring(n)
子串 s1.substring(a,b)
寻找字符 s1.indexOf(c)
寻找字符 s1.indexOf(c,n)
寻找字符串 s1.indexOf(s2)
判断是否以另一字符串开头 s1.startsWith(s2)
判断是否以另一字符串结尾 s1.endWith(s2)
去除两端空格 s1.trim()
替换 s1.replace(c1,c2)
变为小写 s1.toLowerCase()
变为大写 s1.toUpperCase()
  • 所有的字符串都是不可变的,对它们操作的结果都是制造出新的字符串出来
String s1 = "abcd";
s1.toUpperCase();
System.out.println(s1);
=>abcd 并没有变成大写

s2 = s1.toUpperCase();
System.out.println(s2);
=>ABCD 变成了大写

为什么要这么设计呢?=>个人人为是为了方便项目维护,避免一些字符串操作造成的低级错误

  • 字符串只能通过for循环遍历,不能通过for-each循环
String s1="汉字";
for (int i=0; i<s1.length(); i++){
	System.out.println(s1.charAt(i));
}
=> OK

for (char c : s1){
	...
}
=>Can only iterate over an array or an instance of java.lang.Iterable
  • Switch-Case中使用字符串
switch (s){
case "this":...break;
case "that":...break;
}

Math类

函数 功能
abs() 绝对值
pow()
random() 随机数
round() 四舍五入

函数参数传递

  • 类型不匹配
    =>如果 所需值/形式参数 比 传入值/实际参数 要"宽"(loose),换句话说精度不变低,那么编译器会帮我们自动转换
    char->int->double

  • 传递的是什么?
    =>传值而不是传引用

本地变量

  • 函数每次运行,会产生一个独立的变量空间,在这个空间中的变量,是函数这次运行所独有的,称作本地变量(Local Variable)
  • 定义在函数内部的变量就是本地变量
  • 参数也是本地变量

本地变量的生存周期和作用域

  • 生存期:什么时候出现,什么时候消亡
  • 作用域:在什么范围内可以访问这个变量
  • 对于本地变量,它的生存周期和作用域都在大括号(块)内=>程序在进入块前,其中的变量不存在;离开后,也不存在.
  • 成员变量的生存期是对象的生存期,作用域是类内部的成员函数

类和对象

  • 对象是(类的)实体,需要被创建,为我们做事情

    • 表达东西或事件
    • 运行时响应消息(提供服务)
  • 类是(对象的)规范,根据类的定义来创建对象

    • 定义属性
    • 就是JAVA中的类型
    • 可以用来定义变量
  • 对象=数据+操作

    • 数据:属性or状态
    • 操作:函数

对象初始化

  • 过程:成员变量初始化=>构造函数=>将对象交给变量管理
  • 成员变量如果没有初始化,编译器会给默认的"零值"(boolean=>false,object=>null)
    • 本地变量如果没有初始化,编译器会直接报错
  • 构造函数
    • 与类同名
    • 没有返回类型
    • 可以有多个构造函数,参数表不同=>函数重载
      • 创建对象时给的参数不同,就会自动调用不同的构造函数
      • 通过this()调用其他的构造函数
      • 一个类里同名但参数表不同的函数构成了重载关系

封闭的访问属性

  • private只能修饰成员变量or成员函数
  • 除非必要成员变量尽量设为private=>防止被外界随意修改
  • private是针对类,而不是对象=>同一个类创建的不同对象,可以通过public函数成员互相访问private数据成员

开放的访问属性

  • public=>任何类的函数都能够调用,访问,定义变量
    • Public Type must be defined in its own file=>一个文件=一个编译单元
  • (缺省)friendly=>同一package的其他类可以访问

  • friendly修饰的成员,在其他package无法访问

  • 导入方式

    • import package.class =>调用时使用package.class
    • import package.* =>调用时直接写类名
      • 缺点:重名会冲突
  • package内还可以有package

类变量

  • static修饰的成员变量
  • 这个类的所有对象共享这个变量
  • 可以在类外通过Class.StaticVaribale进行访问

类函数

  • static修饰的函数
  • 函数内不能访问non-static field value
  • 只能访问static函数,成员变量
  • 可以不通过对象直接调用=>不属于任何具体的对象

业务逻辑/接口设计

  • 人机交互和业务逻辑分离
  • 业务逻辑/接口设计只考虑数据本身

泛型容器类

  • 容器类:可以存放任意数量的对象
    • 定义时得给两个类型
      • 容器的类型
      • 元素的类型
      • ArrayList<String> ArraryListOfString = new ArraryList<String>();

ArrayList操作

  • ArrayList.add(element)
  • ArrayList.add(element,index)
  • ArrayList.remove(index)
  • ArrayList.get(index)
  • ArrayList.add(element)
  • ArrayList.size()
  • ArrayList.toArray(array)

对象数组

  • 对象数组中每个元素都是对象的管理者,而不是对象本身
  • 创建对象之后,都是null pointer
  • 对象数组可以使用for-each循环

集合容器

  • HashSet=>集合=>集合中没有重复元素,无序

Hash表

  • HashMap<KeyType,ValueType>

    • Type是WrapperType,不是PrimitiveType
  • HashMap.put(key,value)

  • HashMap.get(key)

  • HashMap.keySet()

    • HashMap.keySet().size()
  • Key是唯一的=>放入两个键值对,键一样,那么先放入的就会被覆盖

继承

  • public class Subclass extends Superclass{...}
  • subclass 无法访问 superclass private 成员变量
    • private=>protected=>子类和同个package可以访问
    • 给superclass写一个constructor,再通过method进行操作
  • super()调用superclass的constructor
    • 可以传参数
  • subclass初始化工程:superclass定义初始化=>自身类定义初始化=>构造函数
  • 如果subclass含有和superclass同名的成员变量
    • 那么superclass的成员变量会被隐藏(一样会创建,但是method操作的是subclass的)
    • superclass的method修改的是superclass的成员变量
    • =>谁的method修改谁的成员变量
  • super.method()调用superclass的method

多态变量

  • 子类和子类型
    • 类就是类型=>子类定义了子类型
    • 子类的对象可以当做父类的对象来使用
      • 赋值给父类的变量
      • 传递给需要父类对象的函数
      • 放进需要父类对象的容器里
  • 多态变量
    • 多态变量:运行时,所管理的变量是会变化的
    • JAVA的对象变量是多态的,它们能保存不止一种类型的对象
      • 声明类型(静态类型)的对象或其子类的对象
      • 把子类对象赋给父类的变量时,就发生了向上造型

向上造型

  • 造型:把一个类型赋给另一个类型
    • 让一个变量去管理一个动态类型与其静态类型不符的对象
    • 造型就是用()围起来放在值的前面
  • 对象的赋值
    • 不是拿一个对象给另一个对象赋值
    • 而是让两个对象的管理者,共同管理同一个对象
  • 子类对象可以赋值给父类变量
    • 父类对象不能赋值给子类变量
      • 除非强制造型SubclassVariable=(Subclass)SuperclassObj;
        • 这种转换不一定是安全的
        • 对象本身没有发生任何变化=>不是类型转换
          • 类型转化完,对象本身就发生了彻底地变化
        • 运行时有机制检查转化是否合理=>ClassCastException
  • 向上造型
    • 拿一个子类的对象当做父类的对象来用
    • 向上造型是默认的,不需要运算符
    • 向上造型总是安全的

多态

  • 函数调用的绑定
    • 绑定:通过对象变量调用函数,调用哪个函数这个事件叫做绑定
      • 静态绑定:根据变量的声明类型来决定
      • 动态绑定:根据变量的动态类型来决定
  • 在成员函数中调用其他成员函数也是通过this这个对象变量来调用的=>所有成员函数的调用都应该被看做一种动态绑定
  • 覆盖override
    • 子类和父类中存在名称和参数表完全相同的函数,这一对函数构成覆盖关系
    • 通过父类的变量调用存在覆盖关系的函数时,会调用变量当时所管理对象所属的类的函数
  • 多态:通过一个变量去调用一个函数,不关心实际类型是什么(不需要去判断),对应的函数就会被调用

Object类

  • JAVA的单根结构:Object类是所有类的Root=>所有类都是Object类的子类
  • Object类的函数
    • toString()
    • equals()
    • notify()
    • ...
  • override methods
    • @Override
    • 覆盖父类的方法
      • 要和父类函数有相同的函数原型(名字,参数表,都是public)

消除代码复制

  • 代码复制是设计不良的一种表现=>消除代码复制(提取重复代码到函数,再调用)

封装

  • 增加可扩展性
    • 可运行的代码!=良好的代码
    • 对代码做维护时最能看出代码质量
  • 用封装降低耦合
    • 类和类之间的关系称作耦合
      • 耦合越低越好,保持距离是形成良好代码的关键
    • 具体措施
      • 将成员变量设为私有
      • 对成员变量的操作封装为函数
        • 不是简单的get,而是需要加以逻辑判断,或者数据结构的修改

可扩展性

  • 用接口实现聚合
  • 用框架+数据提高可扩展性
    • 出口:成员变量做硬编码=>用容器+method(形成框架)
    • 命令解析脱离if-else
    • 定义一个handler来处理命令
    • 用hashmap来存储命令和handler之间的关系
    • 使交互部分代码得以复用,且新增功能只需添加handler

抽象

  • 抽象函数:表达概念而无法实现具体代码的函数,带有abstract修饰符
  • 抽象类:表达概念而无法构造出实体的类
  • 限定
    • 抽象函数只有声明,没有定义
    • 包含抽象函数的类必须是抽象类
    • 抽象类不能产生对象
      • 但是可以定义变量,用于接收改抽象类子类的实例
  • 继承抽象类的子类必须覆盖父类中的抽象函数(implementation)
    • 否则自己成为抽象类=>无法实例化
  • 两种抽象的概念
    • 与具体相对=>表示一种概念而非实体
    • 与细节相对=>表示一定程度上忽略细节,着眼大局

接口

  • 接口是纯抽象类
    • 所以成员函数都是抽象函数
    • 所以成员变量都是public static final
  • 接口规定长什么样,但是不管里面有什么
  • 实现接口
    • 类用extends,接口用Implements
    • 类可以实现多个接口
    • 接口可以继承接口,但是不能继承类
    • 即可不能实现接口
  • 面向接口编程
    • 为了解决一个问题,先定义各个接口,然后再实现类
    • 任何需要在函数间传入传出的一定是接口,而不是具体的类=>使得JAVA适合多人协作,编写大型程序(+)=>代码量快速膨胀(-)

2021年4月24日01:34:02:未完待续

内部类

  • 在类内部的类
  • 和其他数据/函数一样是外部类的成员=>有成员的权利,能够访问外部类的成员(包括private member)

匿名类

  • 在new对象时给出定义,形成匿名类
  • 匿名类可以继承某个类,或者实现某个接口
  • Swing消息机制广泛使用匿名类=>减少大量函数声明

MVC设计模式

  • 表现和数据分离的同时,加入控制control=>根据用户的输入对model进行调整
  • View和Controller之间没有直接联系
    • control通过修改model,来对view进行修改=>降低耦合,简化VIEW

异常捕捉

  • try{...}catch(XException e){...}
  • 一个try,可以堆叠多个catch

异常捕捉机制

  • 有异常抛出
位置 行为
在函数 返回调用者
在try 执行catch
其他情况 退到外层

捕捉到异常

捕捉到异常,可以对异常对象做什么?

  • e.getMessage()
  • e.toString()
  • e.printStackTrace()
  • throw e=>将异常交给上层处理

异常

  • 有不寻常的事情发生,停止原本要做的事,让其他地方的代码来处理
  • 清晰区分了业务逻辑代码和异常处理代码
    • 相较传统的通过ErrorCode和层层嵌套的if进行异常处理,二者夹杂在一起

异常抛出与声明

  • 抛出异常的地方
    • 添加throw声明(函数声明)
    • 用try-catch包括起来
  • XException继承自Exception
    • Exception继承自Throwable

运行时异常

  • 类似于ZeroDivisionException之类的大量运行时会产生的异常
  • 每种情况都catch处理会让代码量急剧膨胀
  • 可以使用catch(Execption e){...}捕获所有异常来统一处理=>避免过多的异常处理代码

  • 流是IO的方式
  • 流是单向的

流的基础类

  • InputStream
  • OutputStream
  • 二者都是以字节为操作单位的

文件流

  • FileInputStream
  • FileOutputSteam

流过滤器

  • 将输入流转化为特定编码格式

文本流

  • InputStream/OutputStream只能处理Byte
  • 处理文本用Reader/Writer=>处理Unicode字符
  • 文件不一定是Unicode编码
    =>可以借助Stream打开文件,再通过过滤器,转化为Unicode,再传给Reader/Writer

汉字编码

  • GBK和UTF-8
  • InputStreamReader(InputStream,Charset)指定Charset打开

格式化输入输出

  • PrintWriter
    • format()
    • print()
    • printf()
    • println()
  • Scanner
    • next...()
  • 如何选择Stream/Reader/Scanner
    • Binary=>Stream
    • Text=>Reader
    • Other(Data)=>Scanner

流的应用

  • 常用于内存数据或网络通信
  • Read和其他的ReadLine(),nextInt()等基于它的函数都是阻塞的,在得到所需内容前会停来
  • 要改阻塞为非阻塞有两种办法
    • 多线程
    • NIO的channel选择机制

对象序列化

  • 将对象转化为文本
  • ObjectInputStream
    • ReadObject()
  • ObjectOutputStream
  • Serialization Interface

2021年4月27日16:51:12:到这里课程就结束了.感觉翁恺老师这门课是真的神,尤其是OOP和后面的异常,流讲特别好,深入浅出.
不过我一下子应该不能全部消化.这可以做个roadmap,之后逐块深入.

原文地址:https://www.cnblogs.com/rpish/p/14696101.html