java随手记 面向对象
// 可以把两个类放在同一个文件中,但文件中只能有一个类是公共类,且公共类必须与文件同名,即xxx.java,源代码中的每个类编译成class文件
// java库中的类
// java.util.*
// Date类 Date() 针对当前时间创建一个Date对象
Date(elapseTime) elapseTime: long 针对一个从格林威治时间1970.1.1至今流逝的以毫秒为单位计算的给定时间创建Date对象
toString() 返回一个代表日期和时间的字符串表示 string
getTIme() 返回从格林威治时间1970.1.1至今流逝的毫秒数 long
setTime(elapseTime) elapseTime: long 在对象中设置一个新的流逝时间
e.g. Date date = new Date();
System.out.println(date.getTIme() + "milliseconds");
System.out.println(date.toString);
// Random类 Random() 以当前时间作为种子创建一个Random对象
Random(seed) seed: long 以一个特定值作为种子创建一个Random对象 若多个对象种子相同 则将产生相同的值
nextInt/Long/Boolean 返回一个随机的对应类型的值
nextInt(n) n: int 返回一个0到n之间的随机int值
nextDouble/Float 返回一个0.0/0.0F到1.0/1.0F(不包含)之间的随机对应类型的值
e.g. Random generator = new Random(3);
System.out.print(generator.nextInt(1000));
可以使用java.security.SecureRandom类来产生随机数字,这种产生的随机数是不确定的,故而安全
// javafx.geometry
// Point2D类 Point2D(x, y) x,y: double 用给定的x,y坐标创建一个Point2D对象
distance(x, y) x,y: double 返回该点到(x,y)的距离 double
distance(p) p: Point2D 返回该点到指定点p之间的距离 double
getX() 返回x坐标 getY() 返回y坐标 double
midpoint(p) p: Point2D 返回该点与点p的中间点 Point2D
toString() 返回该点的字符串表示 string
e.g. toString()输出形式为 Point2D [x = xxx, y = xxx
// 静态变量 可被一个类的所有对象所共享 static elementType name; 若某个对象修改了静态变量的值,同一个类的所有对象都受到影响
// 静态常量 final static double PI = 3.14159
// 静态方法 static typeName name(){}
// 实例方法和实例数据须在实例创建后才能使用,通过引用变量访问,静态方法和静态数据可以通过引用变量或它们的类名来调用
// 不能在静态方法中直接调用实例方法和实例数据域,如main中,可先设立一个引用变量,在通过引用变量调用,具体见P294《梁勇,java1》
// 最好通过类名来调用静态方法和数据,提高可读性,便于他人识别静态变量
// 可以在类 方法 数据域前加public可见性修饰符 表示他们可以被任何其他的类访问
// 如果没有使用可见性修饰符 默认只可以被同一个包中的任何一个类访问
// private修饰符限定方法和数据域只能在它自己的类中被访问
// 不能在局部变量上使用public和private,private只能用在类的成员上,public可用于类和类的成员
// 数据域封装 使用private修饰符将数据声明为私有的
// 为了客户访问私有数据域 可以提供一个获取(getter)方法返回数据域的值 称为访问器(accessor)
// 形式为 public returnType getPropertyName() 如果是boolean型 一般是isPropertyName
// 为了更新数据域 可以提供一个设置方法(setter)方法给数据域设置新值 称为修改器(mutator)
// 形式为 public void setPropertyName(dataType PropertyValue)
// e.g. private double radius = 1; // 私有数据
public void setRadius(double newRadius) {
radius = (newRadius >= 0) ? newRadius : 0;
} // 设置方法
// 从现在开始 除非特定 否则所有数据域都应被声明为私有的 所有的构造方法和方法应该被声明为公共的
// 给方法传递一个对象 是将对象的引用传递给方法
// 对象数组 e.g. Circle[] circleArray = new Circle[10];
for(int i = 0; i < circleArray.length; i++) {
circleArray[i] = new Circle();
}
// 不可变对象 : 如String类
// 不可变类 要求:所有数据域都是私有的 没有修改器方法(mutator) 没有返回一个指向可变数据域的引用的访问器方法(accessor)
// 一个类中的实例变量和静态变量称为类变量或数据域 在方法内部定义的变量称为局部变量
// 无论在何处声明 类变量的作用域都是整个类 类的变量和方法可以在类中以任意顺序出现 但当一个数据域是基于对另一个的引用时 要有顺序
// 局部变量和类变量同名是被允许的 局部变量会优先 此时类变量会被隐藏 但除方法中的参数一般不要这么做
// this可以引用对象的实例成员 通常可省略 但在引用被方法或者构造方法的参数所隐藏的数据域以及调用一个重载的构造方法时 this引用是必需的
// e.g. private double radius;
public Circle() { };
public Circle(double radius) {
this.radius = radius; // 此处即第一种情况 参数被隐藏
}
public Circle() {
this(1.0); // 此处即第二种情况 用于调用另外一个构造方法 注意 java要求在构造方法中使用语句this()应在其他可执行语句之前
}
// 类的关系包含关联 聚集 组合 继承 (注意:是类之间的关系!)
// 关联 如学生选取课程是Student类和course类的关联
// e.g. public class Student {
private Course[] courseList;
public void addCourse(Course c){ ... }
}
public class Course {
private Student[] classLIst;
public void addStudent(Student s){ ... }
}
// 聚集 两个对象之间的归属关系 是关联的一种特殊形式 如学生和地址
// 组合 若被聚集对象的存在依赖于聚集对象 称这两个对象之间的关系为组合 如学生和名字
// 将基本数据类型值作为包装类对象处理(装箱) 即java.lang包中提供的Integer等包装类(不需要import)
// 既可以用基本数据类型值也可以用表示数值的字符串来构造包装类 如 new Double(5.0) 或 new Double("5.0")
// 类中包含方法有 (以Integer类为例)
typeValue(): type 即对应type类型的转换,输出为对应type类型
e.g. doubleValue(): double
compareTo(o: Integer): Integer 比较两个数值大小,分别返回1,0,-1
valueOf(s: string): Integer 创建一个新Integer类对象,并将它初始化为指定string s表示的值
e.g. Integer integerObject = Integer.valueOf("12");
parseInt(s: string): int 将一个字符串转换为一个int值
parseInt(s: string, radix: int): int 将数值字符串转换为正确的以radix进制为基数的数值
e.g. Integer.parseInt("1A" , 16) returns 26;
// 基本类型与包装类类型之间的自动转换
// 装箱的反过程为拆箱 java允许基本类型和包装类类型间进行自动转换
// e.g. Integer[] intArray = {1, 2, 3}; //此处被自动装箱为new Integer(1),new Integer(2),new Integer(3)
System.out.println(intArray[0] + intArray[1] + intArray[2]); //此处对象intArray[0]等被自动拆箱成int值,然后相加
// BigInteger和BigDecimal类可用于表示任意大小和精度的整数或者十进制数 属于java.math包
// 可以用BigInteger的实例表示任意大小的整数 new BigInteger(String) 可以用BigDecimal的实例表示任意精度的数 new BigDecimal(String)
// 可使用add,subtract,multiply,divide和remainder方法来进行算术运算 用compareTo方法比较两个大数字
// e.g. BigInteger a = new BigInteger(3481431748701246102184781374233231);
BigInteger b = new BigInteger(2);
BigInteger c = a.multiply(b);
BigDecimal a = new BigDecimal(1.0);
BigDecimal b = new BigDecimal(3);
BigDecimal c = a.divide(b, 20, BigDecimal.ROUND_UP); //c = 0.33333333333333333334(20位)
此处使用了重载的divide方法 20指小数点后位数 BigDecimal.ROUND_UP是舍入方式
// String类具体常用方法见(p111, p335, java,梁勇) 注意 String对象是不可改变的 一旦创建 内容不能再修改
// 方法包括
// p335 字符串构造 替换和拆分字符串 使用正则表达式匹配,替换和拆分 字符串和数组之间的转换 将字符和数值转换成字符串 格式化字符串
// p111 获取长度 从字符串中获取字符 连接字符串 字符串的转换 从控制台读取字符串和字符 字符串比较 获得子字符串 获取字符串中字符或子串
// StringBuilder类 StringBuffer类 可以给一个StringBuilder或StringBuffer对象添加,插入新内容 但String类不可以
// 子类调用父类 e.g. public class Circle extends GeometricObject{ }
// 在java中 如果使用extends关键字来定义一个子类 它只允许有一个父类 多重继承可以通过接口来实现
// 子类重载的构造方法
e.g. public Circle(double radius, String color, boolean filled) {
this.radius = radius;
setColor(color); // 注意:一般父类的数据域都是private的 所以此处不能用this 访问不到也无法设置
setFilled(filled); 只能通过父类的getter和setter访问或设置
}
public Circle(double radius, String color, boolean filled) {
super(color, filled); // 可以通过super()或super(arguments)来调用父类的无参或有参构造
this.radius = radius; 但注意 super必须出现在子类构造方法中的第一行,这是显式调用父类构造的唯一方式
} 若未显式调用 编译器会自动将super()作为构造方法的第一条语句
// 在任何情况下 构造一个类的实例时 将会调用沿着继承链的所有父类的构造方法
// 子类首先调用父类的构造 若父类继承与其他类 则先调用父类的父类的构造方法 以此类推 这就是构造方法链
// super也可以调用父类的普通方法 如super.方法名(参数) 若不是子类对父类的方法重写 一般情况下super省略 因为方法已被子类继承 可直接调用
// Circle的子类不能通过super.super.toString()来访问定义在GeometricObject中的方法
// 子类需要修改父类中定义的方法的实现 这称为方法重写
// e.g. public String toString() {
return super.toString() + "\nradius is " + radius; // 注意 此处的super不能省略
}
// 注意 重写的方法必须与被重写的方法名保持一致 且返回类型相同或兼容 兼容的含义是重写的方法的返回类型可以是被重写方法返回类型的子类型
只有当实例方法可访问时 它才能被重写 私有方法不可以
静态方法可以被继承 但不可以被重写 若父类的静态方法在子类中被重新定义 父类中的静态方法将被隐藏
可通过使用语法"父类名.静态方法名"调用隐藏的静态方法
// 重载是使用同样的名字但是不同的签名(参数列表)来定义多个方法 重写是在子类中提供一个对方法的新的实现
// 重载可以发生在同一个类中 也可以发生在具有继承关系的不同类中 重写发生在具有继承关系的不同类中
// 重载具有相同的名字但是不同的参数列表 重写具有相同的签名
// @Override 标注表示被标注的方法必须重写父类的一个方法 若未重写 编译器将会报告一个错误
// e.g. @Override
public String toString(){ }
// 多态: 使用父类对象的地方都可以使用子类的对象 即父类型的变量可以引用子类型的对象
// e.g. public class wuhuqifei {
public static void main(String[] args) {
displayObject(new Circle(1, "red", false));
displayObject(new Rectangle(1, 1, "black", true));
}
public static void displayObject(GeometricObject object) {
System.out.println( ... );
}
// 动态绑定 e.g. Object o = new GeometricObject();
System.out.println(o.toString());
// 声明类型: 一个变量被声明为某种类型 这里o的声明类型为Object 实例可以由声明类型或它的子类型的构造方法创建
// 实际类型: 被变量引用地对象的实际类 这里o的实际类型为GeometricObject
// o调用哪一种toString()方法由实际类型决定 这称为动态绑定
// 动态绑定工作机制: 假设对象o是c1 c2 ... cn的实例 其中c1为c2子类... 也就是说 cn是最通用的类 c1是最特殊的类 在java中 cn是Object类
如果o调用一个方法p 那么JVM会依次在c1 c2 ... cn中查找方法p的实现 直到找到为止 一旦找到一个实现 会立刻停止然后调用
// 对象转换:隐式转换与显式转换
// Object o = new Student()是合法的 因为Student是Object的实例 它称为隐式转换
// 但Student b = o不行 因为Object不一定是Student的实例 需要使用显式转换
// Student b = (Student)o 这就是一个显式转换
在同一类内可访问 在同一包内可访问 在不同包中的子类内可访问 在不同包内可访问
public √ √ √ √
protected √ √ √
default √ √
private √
// class前无修饰符就是default
// 子类可以重写父类的protected方法 并把它的可见性改为public 但子类不能削弱父类中定义的方法的可访问性 如父类为public 子类也应为public
// 防止继承和重写
// public final class A{...} 使用final修饰符表明一个类是最终类 不能作为父类 即不能被继承
// Math String StringBuffer StringBuilder等以及所有基本数据类型的包装类都是最终类
// public final void m(){...} 使用final修饰符也可以定义一个方法为最终的 不能被它的子类重写
// 异常处理 (p394, 梁勇, java1)
// try {
Code to run;
A statement or a method that may throw an exception; // 可能抛出异常的语句
More code to run;
}
catch(type ex){ // type为异常类型
Code to process the exception; // 此处为处理异常的方法
}
// 异常类型 /-- ClassNotFoundException
Exception --- IOException
/ \-- RuntimeException
/
Object---Throwable
\ /--- LinkageError
Error---- VirtualMachineError
// 系统错误: 由java虚拟机抛出 用Error类表示 Error类描述的是内部系统错误 如果发生 除了通知用户以及尽量稳妥的终止程序外 几乎什么都不能做
// e.g. LinkageError : 一个类依赖于另一个类 但是在编译前者后 后者进行了修改 出现不兼容
VirtualMachineError : java虚拟机崩溃 或者继续运行所必需的资源已经耗尽
// 异常:用Exception类表示 描述的是你的程序与外部环境所引起的错误 这些错误能被程序捕获和处理
// e.g. ClassNotFoundException : 试图使用一个不存在的类 如运行一个不存在的类 要调用三个类只能找到两个
IOException : 同输入输出相关的操作 如无效的输入 读文件时超过文件尾 打开一个不存在的文件等
// 运行时异常:用RuntimeException类表示 描述的是程序设计错误 如错误的类型转换 访问一个越界数组或数值错误 通常表明了编程错误
// e.g. ArithmeticException : 一个整数除以0 注意 浮点数的算术运算不抛出异常
NullPointerException : 试图通过一个null引用变量访问一个对象
IndexOutOfBoundsException : 数组的下标超出范围
IllegalArgumentException : 传递给方法的参数非法或不合适
// RuntimeException Error以及它们的子类都称为免检异常 所有其他异常都称为必检异常
// 必检异常强制要求程序员检查并通过try-catch块处理它们 或者在方法头进行声明 java不强制要求编写代码捕获或声明免检异常
// 1.声明异常 public void myMethod() throws IOException 关键字throws表明方法可能会抛出异常IOException
如果方法可能会抛出多个异常 可以在关键字 throws 后添加一个用逗号分隔的异常列表
public void myMethod() throws Exception1, Exception2, Exception3, ...
2.抛出异常 检测到错误的程序可以创建一个合适的异常类型的实例并抛出它 关键字为throw 例如:
IllegalArgumentException ex = new IllegalArgumentException("Wrong Argument");
throw ex;
或者下面的语句
throw new IllegalArgumentException("Wrong Argument");
3.捕获异常 如果在执行try块的过程中没有出现异常 则跳过catch子句 //具体描述及调用顺序见(p400, 梁勇, java1)
若try块中某条语句抛出一个异常 Java就会跳过try块中剩余的子句 然后开始查找处理这个异常的代码
处理这个代码称为异常处理器 可以从当前的方法开始 沿着方法调用链寻找 若满足判断 则会执行catch中代码
若在该块中没有发现异常处理器 java会退出这个方法 把异常传递给这个方法的调用者 然后继续查找处理器
如果在调用的方法链中找不到处理器 程序就会直接终止 并在控制台上打印出错信息 查找处理器的过程称为捕获一个异常
try{
statements; // 可能抛出异常的语句
}
catch(Exception1exVar1){
handler for exception1;
}
catch(Exception2exVar2){
handler for exception2;
}
...
catch(Exception1exVarN){
handler for exceptionN;
}
注意 各种异常类可以从一个共同的父类派生 若一个catch块可以捕获一个父类的异常对象 它就能捕获那个父类所有子类的异常对象
注意 在catch块中异常被指定的顺序是非常重要的 若父类的catch块出现在子类的catch块之前 就会导致编译错误
4.从异常中获取信息 以下属于java.lang.Throwable类 具体使用方法见(p402, 梁勇, java1)
getMessage():string 返回描述该异常对象的信息
toString():string 返回三个字符串的连接 1.异常类的全名 2.": " 3.getMessage()方法
printStackTrace():void 在控制台上打印Throwable对象和它的调用栈的跟踪信息
getStackTrace():StackTraceElement[] 返回一个栈跟踪元素的数组 表示和该异常对象相关的栈的跟踪信息
// finally子句 用来实现无论异常是否出现或者被捕获都执行某些代码 格式如下
try {
statements;
}
catch(TheException1ex){
handling ex;
}
finally {
finalStatements;
}
在任何情况下 finally块中的代码都会执行 不论try块中是否出现异常或者是否被捕获 考虑如下情况
1.若try块中没有出现异常 执行finalStatements 然后执行try语句的下一条语句
2.若try块中有一条语句引起了异常并被catch块捕获 会跳过try块中的其他语句 执行catch和finally子句 再执行try语句的下一条语句
3.若try块中的一条语句引起异常但并未被任何catch块捕获 就会跳过try块中语句 执行finally子句 并把异常传递给这个方法的调用者
即使在到达finally块之前有一个return语句 finally块还是会执行
e.g. try {
statement1; //若无异常发生 会执行4和5
statement2; 若异常类型为Exception1 会执行4和5
statement3; 若异常类型不是Exception1 会执行4 不会执行5
}
catch (Exception ex1){ }
finally {
statement4;
}
statement5;
// 何时使用异常 当必须处理不可预料的错误状况时应该使用它 注意不要把异常处理错误用来做简单的逻辑测试
// 重新抛出异常 如果异常处理器不能处理一个异常 或者只是简单的希望它的调用者注意到该异常 java允许该异常处理器重新抛出异常
语法如下:
try{ 、
statements;
}
catch(TheExceptionex) {
perform operations before exits;
throw ex; // throw ex语句重新抛出异常给调用者 以便调用者的其他处理器获得处理异常ex的机会
}
// 链式异常 与另一个异常一起抛出一个异常 构成了链式异常
// 创建自定义异常类 可以通过继承java.lang.Exception类或其子类来定义一个自定义异常类 但尽量不要这么做
最好使自定义异常是必检的 具体创建见(p412, 梁勇, java1)
// 文件处理 java.io.File File类中包含大量对文件处理的方法 具体见(p413, 梁勇, java1)
// 文件的输入与输出
// 1.文本文件
使用PrintWriter写数据 向文件写入
java.io.PrintWriter类可用来创建一个文件并向文本文件写入数据 首先 必须为一个文本文件创建一个PrintWriter对象 如下
PrintWriter output = new PrintWriter(filename);
e.g. public class WriteData{
public static void main(String[] args) throws java.io.IOException{
java.io.File file = new java.io.File("scores.txt");
if(file.exists()){ // 检测该文件是否存在 若存在则退出程序
System.out.println("File already exists");
System.exit(1);
}
java.io.PrintWriter output = new java.io.PrintWriter(file); // 该文件若不存在 创建一个新文件
output.print("John T Smith ");
output.println(90);
output.print("Eric K Jones ");
output.println(85);
output.close(); // 使用close()方法关闭文件
}
}
使用try-with-resources自动关闭资源
该语法能在完成语句后自动关闭文件 具体使用方法如下
try(声明和创建资源) {
使用资源来处理文件;
}
注意 资源必须是AutoClosealbe的子类型 比如PrintWriter 才具有一个close()方法
资源的声明与创建必须在同一行语句中 可以在括号中进行多个资源的声明和创建
e.g. public class WriteDataWithAutoClose{
public static void main(String[] args) throws Exception{
java.io.File file = new java.io.File("scores.txt");
if(file.exists()){
System.out.println("File already exists");
System.exit(1);
}
try(java.io.PrintWriter output = new java.io.PrintWriter(file);) {
output.print("John T Smith ");
output.println(90);
output.print("Eric K Jones ");
output.println(85);
}
}
}
使用Scanner读取数据 从文件中读取数据
Scanner input = new Scanner(new File(filename));
hasNext():boolean 如果Scanner还有更多的数据可以读取 则返回true
next():String 从Scanner中读取下一个标记作为字符串返回
nextLine():String 从Scanner中读取一行 以换行结束
nextInt():int 从Scanner中读取下一个标记作为int值返回
useDelimiter(pattern:String):Scanner 设置Scanner的分隔符 并且返回Scanner
e.g. scores.txt John T Smith 90
Eric K Jones 85
import java.util.Scanner;
public class ReadData {
public static void main(String[] args) throws Exception {
java.io.File file = new java.io.File("scores.txt");
Scanner input = new Scanner(file);
While(input.hasNext()) {
String firstName = input.next();
String mi = input.next();
String lastName = input.next();
int score = input.nextInt();
System.out.println(firstName + " " + mi + " " + lastName + " " + score);
}
input.close();
}
}
// 2.
// 抽象类:抽象类不可用于创建对象 抽象类可以包含抽象方法 这些方法将在具体的子类中实现 在类的头部使用abstract修饰符表示该类为抽象类
// 若某方法在子类中都包含 则可设置为抽象方法 在方法头使用abstract修饰符表示
// 抽象类不能用new创建它的实例 抽象方法只有定义没有实现 一个包含抽象方法的类必须声明为抽象类
// 抽象类的构造方法定义为protected 因为它只被子类调用 创建一个具体子类的实例时 父类的构造方法被调用以初始化父类中定义的数据域
// 注意:1.抽象方法不能包含在非抽象类中 在继承自抽象类的非抽象子类中 必须实现所有的抽象方法 若不能实现 则该子类也需定义为抽象的 抽象方法是非静态的
2.抽象类不能使用new来初始化 但仍然可以定义它的构造方法 可在子类的构造方法中调用
3.包含抽象方法的类必须是抽象的 但可以定义一个不含抽象方法的抽象类
4.子类可以重写父类的方法并把它定义为抽象的
5.即使父类是具体的 子类也可以是抽象的 如Object类是具体的 但是它的子类可以是抽象的
6.不能使用new操作符从一个抽象类创建一个实例 但是抽象类可以用作一种数据类型 如创建一个元素是抽象类类型的数组
// 接口:目的是指明相关或者不相关类的对象的共同行为 例如 使用适当的接口 可以指明这些对象是可比较的,可食用的或者可克隆的
// 接口的定义 e.g. public interface Edible{ }
// 在java中 接口被看作是一种特殊的类 接口的使用有点像使用抽象类 如可使用接口作为引用变量的数据类型或类型转换的结果等 不能使用new操作符创建接口的实例
// 使用implements关键字让对象所属的类实现接口 e.g. class Chicken extends Animal implements Edible{ }
// 接口的所有数据域都是public static final 所有的方法都是public abstract java允许在接口定义中省略这些修饰符
// e.g. public interface T {
int k = 1; // 尽管public修饰符对于定义在接口中的方法可以省略 但在子类实现时方法必须定义为public的
void p();
}
// java8允许接口中存在公有的静态方法 接口中的公有静态方法和类中的公有静态方法使用相同 如下
// e.g. public interface A {
public default void doSomething() {
System.out.println("Do something");
}
public static int getAValue() {
return 0;
}
}
// java8引入了使用关键字default的默认接口方法 一个默认接口方法为接口中的方法提供了一个新的默认实现
// 实现该接口的类可以简单的使用方法的默认实现 或者使用一个新的实现方法来重写该方法
// 利用该特征可以在一个具有默认实现的已有接口中添加一个新的方法 并且无须为实现了该接口的已有类重新编写代码
// Comparable接口
// 定义:package java.lang
public interface Comparable<E> {
public int compareTo(E o); // compareTo方法判断这个对象相对于给定对象o的顺序 小于等于大于分别返回-1,0,1
}
// Comparable接口是一个泛型接口 在实现该接口时 泛型类型E被替换成一种具体的类型
// 在java.util.Arrays.sort(Object[])方法中就可以使用compareTo方法来对数组中的对象进行比较和排序 如
// sort不能排序一个Rectangle类 因为Rectangle类没有实现接口Comparable 所以可定义一个新的ComparableRectangle类来实现接口 如
// e.g. public class ComparableRectangle extends Rectangle implements Comparable<ComparableRectangle> {
......
@Override
public int compareTo(ComparableRectangle o){
if(getArea() > o.getArea)
return 1;
else if(getArea() < o.getArea())
return -1; // 一般在重写排序中的compareTo方法时 也要重写Object类中的equals()方法
else
return 0;
}
@Override
public String toString() {
return super.toString() + " Area: " + getArea();
}
}
// Cloneable接口
// Cloneable接口指定了一个对象可以被克隆
// 定义:package java.lang;
public interface Cloneable {
}
// 该接口为空的 一个方法体为空的接口称为标记接口 既不包括常量也不包括方法 用于表示一个类拥有某些希望具有的特征
// 实现Cloneable接口的类标记为可克隆的 而且它的对象可以使用定义在Object类中的clone()方法克隆
// 在Object类中定义的clone()方法头为 protected native Object clone() throws CloneNotSupportedException;
// native关键字表明这个方法是jvm针对本地平台实现的 不需要我们实现
// protected关键字表明我们在调用时必须在类中重写该方法 并将可见性修饰符改为public 这样就可以在任何一个包中使用
// 深复制与浅复制(深拷贝与浅拷贝)
// 浅拷贝:被复制对象的所有变量都含有与原来对象相同的值,而所有其他对象的引用仍然指向原来的对象。
即对于原对象的的数据域 若为基本类型 则复制值 若数据域为对象 则复制的是该对象的引用
e.g. house1==house2 false 因为复制前后是两个对象 但house1.whenBuilt==house2.whenBuilt为true 因为指向的是同一个对象 即house1.whenBuilt
当复制对象的数据域含有对象时,如果希望原来的引用指向被复制的新对象,则要实现深拷贝
浅拷贝通常实现方法为:
@Override
public Object clone(){
try{
return super.clone();
}
catch(CloneNotSupportedException ex){
return null;
}
}
// 深拷贝:被复制对象的所有变量都含有与原来对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制的新对象
而不再是原有的那些被引用的对象 换言之,深复制把复制的对象所引用的对象都复制了一遍
进行完深复制后house1.whenBuilt==house2.whenBuilt为false 因为两个对象指向的引用不同
深拷贝通常实现方法:
public Object clone() {
try{
House houseClone = (House)super.clone();
houseClone.whenBuilt = (java.util.Date)(whenBuilt.clone());
return houseClone;
}
catch(CloneNotSupportedException ex){
return null;
}
}
// 关于深拷贝与浅拷贝的理解 具体可参考https://www.cnblogs.com/ysocean/p/8482979.html
// 抽象类 变量:无限制
构造方法:子类通过构造方法链调用构造方法 抽象类不能用new操作符实例化
方法:无限制
接口 变量:所有的变量必须是public static final
构造方法:没有构造方法 接口不能用new操作符实例化
方法:可以包含public的抽象实例方法,public的默认方法以及public的静态方法
// java只允许类的继承做单一继承 但是允许使用接口做多重继承 例如
public class NewClass extends BaseClass implements Interface1, ... ,InterfaceN{}
// 利用关键字extends 接口可以继承其他接口 这样的接口称为子接口 例如下面NewInterface是Interface1, ... ,InterfaceN的子接口
public interface NewInterface extends Interface1, ... ,InterfaceN{}
// 一个实现NewInterface的类必须实现在NewInterface, Interface1, ... ,InterfaceN中定义的抽象方法 通常 推荐使用接口而非抽象类
java随手记 面向对象的更多相关文章
- 0030 Java学习笔记-面向对象-垃圾回收、(强、软、弱、虚)引用
垃圾回收特点 垃圾:程序运行过程中,会为对象.数组等分配内存,运行过程中或结束后,这些对象可能就没用了,没有变量再指向它们,这时候,它们就成了垃圾,等着垃圾回收程序的回收再利用 Java的垃圾回收机制 ...
- 0028 Java学习笔记-面向对象-Lambda表达式
匿名内部类与Lambda表达式示例 下面代码来源于:0027 Java学习笔记-面向对象-(非静态.静态.局部.匿名)内部类 package testpack; public class Test1{ ...
- 0025 Java学习笔记-面向对象-final修饰符、不可变类
final关键字可以用于何处 修饰类:该类不可被继承 修饰变量:该变量一经初始化就不能被重新赋值,即使该值跟初始化的值相同或者指向同一个对象,也不可以 类变量: 实例变量: 形参: 注意可以修饰形参 ...
- [Java入门笔记] 面向对象编程基础(二):方法详解
什么是方法? 简介 在上一篇的blog中,我们知道了方法是类中的一个组成部分,是类或对象的行为特征的抽象. 无论是从语法和功能上来看,方法都有点类似与函数.但是,方法与传统的函数还是有着不同之处: 在 ...
- 0013 Java学习笔记-面向对象-static、静态变量、静态方法、静态块、单例类
static可以修饰哪些成员 成员变量---可以修饰 构造方法---不可以 方法---可以修饰 初始化块---可以修饰 内部类(包括接口.枚举)---可以修饰 总的来说:静态成员不能访问非静态成员 静 ...
- 黑马程序员——【Java基础】——面向对象(二)异常机制、包(Package)
---------- android培训.java培训.期待与您交流! ---------- 一.异常机制 (一)异常概述 1.异常:就是程序在运行时出现不正常情况. 2.异常类:程序在运行时,出现的 ...
- [java学习笔记]java语言核心----面向对象之this关键字
一.this关键字 体现:当成员变量和函数的局部变量重名时,可以使用this关键字来区别:在构造函数中调用其它构造函数 原理: 代表的是当前对象. this就是所在函数 ...
- Java中的面向对象
Java中的面向对象 在软件开发的学习中, 我最先接触的开发语言就是java,但都是简单的函数和循环数组的应用.说道面向对象,第一次看到这个词的时候还是在C#的学习过程中,我记得当时PPT上霸气的解释 ...
- java学习之面向对象概念
思考的两种方式: 举例: 把大象放到冰箱里 一.面向过程 :[打开冰箱->把大象放里面->关上冰箱门]面向过程注重的是过程,也就是(动作[函数]),然后按照动作依次去执行就好了. 代表语言 ...
随机推荐
- Java基础系列(30)- 命令行传参
命令行传参 有时候你希望运行一个程序的时候再传递给它消息.这就要靠传递命令行参数main()函数实现 package method; public class CommandLine { public ...
- 手把手教你 Docker搭建nacos单机版
Docker搭建nacos单机版步骤 一.使用 docker pull nacos/nacos-server 拉取nacos镜像 我这里没有指定版本所以是拉取latest,你也可以使用 docker ...
- str.strip(chars)
strip会去除给定字符串的指定字符,指定字符可以是一个或多个,去除从左右分别进行,没有则忽略,如果需要去除某个中间的字符,必须先去除外围的字符 看几个例子,以s为例,故意设置为非对称结构, s = ...
- Java-基础-JDK动态代理
1. 简介 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 比如:我们在调用 ...
- CF1556E-Equilibrium【栈,树状数组】
正题 题目连接:https://codeforces.com/contest/1556/problem/E 题目大意 两个长度为\(n\)的序列\(a,b\),\(q\)次询问一个区间\([l,r]\ ...
- CF204E-Little Elephant and Strings【广义SAM,线段树合并】
正题 题目链接:https://www.luogu.com.cn/problem/CF204E 题目大意 \(n\)个字符串的一个字符串集合,对于每个字符串求有多少个子串是这个字符串集合中至少\(k\ ...
- P5445-[APIO2019]路灯【set,树状数组套线段树】
正题 题目链接:https://www.luogu.com.cn/problem/P5445 题目大意 \(n+1\)个点,\(i\)和\(i+1\)个点之间有一条边,\(q\)个操作 断开/连接第\ ...
- truncate表时报“唯一/主键被启用的外部关键字引用”解决办法
前言:清空表时提示"唯一/主键被启用的外部关键字引用"这一警告信息 原因:是因为主键被子表引用,所以对主键进行更改就好了 解决: 使用 alter table table_name ...
- FTP和TFTP
文件传输协议 FTP概述: 文件传输协议FTP(File Transfer Protocol)[RFC 959]是互联网上使用最广泛的文件传输协议, FTP提供交互式的访问,允许用户知指明文件类型与格 ...
- oracle基础安全配置
1.oracle中用户密码复杂度配置 1)查看参数 select limit from dba_profiles where resource_name='PASSWORD_VERIFY_FUNCTI ...