Java基础学习笔记
Java基础学习笔记
此笔记记录Java基础中本人认为重要的点,无顺序,不完全
摘录自《Java核心技术 卷1》
以及黑马程序员Java零基础视频教程_上部_——哔哩哔哩_bilibili、黑马程序员Java零基础视频教程_下部——哔哩哔哩_ bilibili
对象与类
封装
封装( encapsulation , 有时称为数据隐藏) 是与对象有关的一个重要概念。从形式上看,封装不过是将数据和行为组合在一个包中, 并对对象的使用者隐藏了数据的实现方式。对象中的数据称为实例域( instance field ), 操纵数据的过程称为方法( method )。 对于每个特定的类实例(对象)都有一组特定的实例域值。这些值的集合就是这个对象的当前状态( state )。
类之间的关系
在类之间, 最常见的关系有
- 依赖(“ uses-a”)
- 聚合(“ has-a”)
- 继承(“ is-a”)
应该尽可能地将相互依赖的类减至最少。如果类 A不知道 B 的存在, 它就不会关心B的任何改变(这意味着B的改变不会导致A产生任何bug)。用软件工程的术语来说,就是让类之间的耦合度最小。
表达类关系的UML符号(Unified Modeling Language , 统一建模语言)
关系 | UML连接符 |
---|---|
继承 | ————–|> |
接口实现 | – – – – –|> |
依赖 | – – – – –> |
聚合 | <>———— |
关联 | ————— |
直接关联 | —————> |
GETTER / SETTER
注意不要编写返回引用可变对象的访问器方法。如果需要返回一个可变对象的引用, 应该首先对它进行克隆(clone) 。否则对引用对象的更改会在造成原私有对象的更改,这一点破坏了封装性。
例:
1 | class Employee{ |
复用构造函数
在构造函数中可用this()引用另一个构造函数,使公共部分的构造函数只用编写一次
例:
1 | class Employee{ |
继承
覆盖方法
若在子代重写父类方法时内部需使用原父类方法,则使用super.父类方法调用原方法
例:
1 | public class Employee{ |
子类构造函数
子类在构造函数中以super()调用父类构造函数!
匿名类
使用
1 | new ParentClass(){ |
来创建匿名类,一般用于对函数传递只用一次的类变量(多态)
继承设计技巧
1.将公共操作和域放在超类
2.不要使用受保护的域
protected机制导致任何子类都能直接访问protected实例域,其次同个包中的所有类都可访问protected实例域,破坏了封装性。
但protected方法对不提供一般用途而应在子类中重新定义的方法有用。
3.使用继承实现”is-a”关系
在不属于”is-a”关系时不要滥用继承。
4.除非所有继承的方法都有意义,否则不要使用继承
5.在覆盖方法时,不要改变预期的行为
6.使用多态, 而非类型信息
无论什么时候,对于下面这种形式的代码
1 | if (x instanceof class1){ |
都应该考虑使用多态性。
若action1与action2表示相同的概念就应该为这个概念定义一个方法,并将其放置在两个类的超类或接口中,然后调用x.action(),以便利用多态性提供的动态分配机制执行相应的动作。
同时,使用多态方法或接口编写的代码比使用对多种类型进行检测的代码更加易于维护和扩展。
枚举Enum
常用方法
1 | static Enum valueOf(Class enumClass, String name) |
返回指定名字、给定类的枚举常量。
1 | String toString() |
返回枚举常量名。
1 | int ordinal() |
返回枚举常量在 enum 声明中的位置,位置从 0 开始计数
1 | int compareTo() |
如果枚举常量出现在 Other 之前, 则返回一个负值;如果 this=other,则返回 0; 否则返回正值。枚举常量的出现次序在 enum 声明中给出。
类设计技巧
应用这些技巧可以使得设计出来的类更具有OOP的专业水准。:)
1.一定要保证数据私有
绝对不要破坏封装性!有时候, 需要编写一个访问器方法或更改器方法,但是最好还是保持实例域的私有性。当数据保持私有时, 它们的表示形式的变化不会对类的使用者产生影响, 即使出现bug也易于检测。
2.一定要对数据初始化
Java不对局部变量进行初始化, 但是会对对象的实例域进行初始化。最好不要依赖于系统的默认值, 而是应该显式地初始化所有的数据, 具体的初始化方式可以是提供默认值, 也可以是在所有构造器中设置默认值。
3.不要在类中使用过多的基本类型
就是说,用其他的类代替多个相关的基本类型的使用。这样会使类更加易于理解且易于修改。
4.不是所有的域都需要独立的域访问器和域更改器
在对象中,常常包含一些不希望别人获得或设置的实例域,此时就无需对其设置访问器与更改器。
5.将职责过多的类进行分解
如果明显地可以将一个复杂的类分解成两个更为简单的类,就应该将其分解。
6.类名和方法名要能够体现它们的职责
与变量应该有一个能够反映其含义的名字一样, 类也应该如此。命名类名的良好习惯是采用一个名词(Order)、 前面有形容词修饰的名词(RushOrder)或动名词(有“ -ing” 后缀)修饰名词(例BillingAddress)。对于方法来说,习惯是访问器方法用小写get开头 (getSalary), 更改器方法用小写的 set开头(setSalary )
7.优先使用不可变的类
更改对象的问题在于, 如果多个线程试图同时更新一个对象,就会发生并发更改。其结果是不可预料的。如果类是不可变的,就可以安全地在多个线程间共享其对象。因此, 要尽可能让类是不可变的, 这是一个很好的想法。对于表示值的类, 如一个字符串或一个时间点,这尤其容易。计算会生成新值, 而不是更新原来的值。当然,并不是所有类都应当是不可变的。
接口
想了想单独放一章吧……不然上面怪挤的
在 Java 程序设计语言中, 接口不是类,而是对类的一组需求描述,这些类要遵从接口描述的统一格式进行定义。
接口中的所有方法自动地属于public。 因此,在接口中声明方法时,不必提供关键字public,但在实现接口时, 必须把方法声明为 public。
接口中绝不含有实例域,但可以包含常量。
接口中也可实现private与static方法。
默认方法
可用default修饰方法,为接口方法提供一个默认实现。
1 | public interface Compareable<T>{ |
lambda表达式
常见类
泛型数组列表 ArrayList
ArrayList类似数组,但在添加或删除元素时, 具有自动调节数组容量的功能。
创建ArrayList
1 | ArrayList<E>(); |
构造一个空数组列表
1 | ArrayList<E>(int initialCapacity); |
用指定容量initialCapacity构造一个空数组列表。
添加元素
1 | boolean add(E obj) |
该方法为数组列表在末端添加一个元素。永远返回true
1 | boolean add(int index, E obj) |
也可使用带索引参数的*add()*方法在指定位置插入元素!!!:)
数组列表管理着对象引用的一个内部数组。最终, 数组的全部空间有可能被用尽。这就显现出数组列表的操作魅力:如果调用*add()*且内部数组已经满了,数组列表就将自动地创建一个更大的数组,并将所有的对象从较小的数组中拷贝到较大的数组中。
修改元素
1 | void set(int index, E obj) |
该方法将第index个元素赋值(下标从1开始),操作将覆盖原有内容。
读取元素
1 | E get(int index) |
该方法返回第index个元素。
删除元素
1 | E remove(int index) |
该方法删除第index个元素,使后面的元素向前移动,被删除的元素由返回值返回。
提前设定元素数量
1 | void ensureCapacity(int capacity); |
确保数组列表在不重新分配存储空间的情况下就能保存给定数量的元素。capacity为需要的存储容量。
读取实际元素数目
1 | int size(); |
该方法将返回数组列表中包含的实际元素数目。(这个值将小于或等于数组列表的容量)
确定元素大小
1 | void trimToSIze(); |
将数组列表的存储容量削减到当前尺寸。
一旦能够确认数组列表的大小不再发生变化,就可以调用*trimToSize()*方法。这个方法将存储区域的大小调整为当前元素数量所需要的存储空间数目。垃圾回收器将回收多余的存储空间。
对数组实施插人和删除元素的操作其效率比较低。对于小型数组来说,这一点不必担心。但如果数组存储的元素数比较多, 又经常需要在中间位置插入、删除元素, 就应该考虑使用链表了~~
包装器
有时, 需要将int这样的基本类型转换为对象。 所有的基本类型都冇一个与之对应的类。例如,Interger类对应基本类型int。通常, 这些类称为包装器(wrapper) 。
这些对象包装器类拥有很明显的名字:Integer、Long、Float、Double、Short、Byte、Character 、Void 和 Boolean (前6 个类派生于公共的超类 Number)。对象包装器类是不可变的,即一旦构造了包装器,就不允许更改包装在其中的值。同时, 对象包装器类还是final, 因此不能定义它们的子类。
在需要使用Integer时若使用int变量,如3,将自动变换成Integer.valueOf(3),这种变换被称为自动装箱(autoboxing),相反也有自动拆箱。
在比较两包装器对象记得使用*equals()*方法!
String转换int
1 | //给定字符串表示的是十进制的整数 |
返回字符串s表示的整型数值
String转换Integer
1 | //进制同上 |
返回用 s 表示的整型数值进行初始化后的一个新 Integer 对象。
Math类
Math类是一个帮助进行数学运算的工具类,其中所有的方法都是静态的。
常见方法:
1 | static int abs(int a) |
–获取参数绝对值
1 | static double ceil(double a) |
–向上取整
1 | static double floor(double a) |
–向下取整
1 | static int round(float a) |
–四舍五入
1 | static int max(int a int b) |
–返回两者中较大值
1 | static double max(double a, double b) |
–返回a的b次幂
1 | static double random() |
–返回 [ 0.0 ~ 1.0 ) 的随机值
System类
System类是提供与系统相关方法的工具类。
常用方法:
1 | static void exit(int status) |
–终止当前运行的java虚拟机
1 | static long currentTimeMillis() |
–返回当前系统的时间毫秒值形式
1 | static void arraycopy(数据源数组, 起始索引,目的地数组,起始索引,拷贝个数) |
–数组拷贝
反射
反射库(reflection library) 提供了一个非常丰富且精心设计的工具集, 以便编写能够动态操纵 Java 代码的程序。
能够分析类能力的程序称为反射(reflective )。反射机制的功能极其强大,在下面可以看到, 反射机制可以用来:
- 在运行时分析类的能力。
- 在运行时查看对象, 例如, 编写一个 toString 方法供所有类使用。
- 实现通用的数组操作代码。
- 利用 Method 对象
==!!!看不太懂而且不知道用处,先不管这玩意==
文档注释
可对类、函数、公有域(通常为静态常量)、包建立注释 论如何变得高级?❤️
注释放置在所描述特性的前面。注释以 /**开始,并以 */ 结束。
每个 /** . . . / 文档注释在标记之后紧跟着自由格式文本( free-form text )。标记由 @开始, 如@author 或@param*。
通用标记:
· @author 姓名
这个标记将产生一个author(姓名)条目
· @version 文本
这个标记将产生一个version(版本)条目,这里的文本可以是对当前版本的任何描述
· @since 文本
这个标记将产生一个since(始于)条目,这里的文本可以是对引入特性的版本描述。例如,@since version 1.7.1
· @deprecated 文本
这个标记将对类、方法或变量添加一个不再使用的注释,文本中给出取代的建议。例如,
1 | /** |
通过*@see和@link标记,可以使用超级链接, 链接到javadoc*文档的相关部分或外部文档。
· @see 引用
这个标记可在”see also”部分增加一个超级链接
第一种情形:
1 | /** |
包名与类名可省去,此时即为当前包及当前类。
第二种情形:
1 | /** |
上述情况都可在后方指定一个可选的标签 label作为链接锚 link anchor,作为显示链接的名称。
若*@see标记后方有一对双引号,引号内的文本会显示在see also*部分。
可以为一个特性添加多个*@see*标记,但必须将它们放在一起。
· @link 引用
可在注释中的任意位置放置指向其他类或方法的超级链接
例如
1 | { package_name.class_name#method_name} |
这里的描述规则与*@see*标记规则一样!
方法注释:
· @param 变量描述
这个标记将对当前方法的param(参数)部分添加一个条目,这个描述可以占据多行, 并可以使用 HTML 标记。一个方法的所有 @param 标记必须放在一起。
· @return 描述
这个标记将对当前方法添加return(返回)部分,这个描述可以跨越多行, 并可以使用 HTML 标记。
· @throw 描述
这个标记将添加一个注释,用于表示这个方法有可能抛出异常。