本文主要是介绍Java SE痛点总结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
- 循环边界
- 访问修饰符
- I/O
- 对象的深拷贝
- 反射
1 循环边界
无论是C++还是Java,基础笔试题里,总会冒出一个“以下循环执行了几次?”的奇妙问题,笔者将while语句实现n次循环的模式总结如下。
(a)
i = 0;
while (i < n) {...i++;
}
(b)
i = 1;
while (i <= n) {...i++;
}
(c)
while (n-- > 0) {...
}
(d)
while (--n >= 0) {...
}
2 访问修饰符
但凡涉及“访问修饰符”的编程语言,都是每个人心中无限的痛,笔者欲通过几段简单的代码,让大家了解Java的访问修饰符。
//同包同类
package com.baidu;public class A {public void pub() {System.out.println("public()");}protected void pro() {System.out.println("protected()");}void def() {System.out.println("default()");}private void pri() {System.out.println("private()");}public static void main(String[] args) {A aa = new A();aa.pub();aa.def();aa.pro();aa.pri();}// Output:// public()// default()// protected()// private()
}
//同包不同类
package com.baidu;public class B {public static void main(String[] args) {A aa = new A();aa.pub();aa.pro();aa.def();
// java: pri() 在 com.baidu.A 中是 private 访问控制/*错误:aa.pri();*/}// Output:// public()// protected()// default()
}
//同包不同类继承
package com.baidu;public class C extends A {public void f() {pub();pro();def();/*pri();*/}
}class D {public static void main(String[] args) {C cc = new C();cc.f();}// Output:// public()// protected()// default()
}
//不同包继承
package com.google;import com.baidu.A;public class E extends A {public void g() {pub();pro();/*def();*//*pri();*/}
}class F {public static void main(String[] args) {E ee = new E();ee.g();}// Output:// public()// protected()
}
//不同包无任何关系的类
package com.google;import com.baidu.A;public class G {public static void main(String[] args) {A aa = new A();aa.pub();
// java: pro() 在 com.baidu.A 中是 protected 访问控制
// java: def()在com.baidu.A中不是公共的; 无法从外部程序包中对其进行访问
// java: pri() 在 com.baidu.A 中是 private 访问控制/*aa.pro();*//*aa.def();*//*aa.pri();*/}// Output:// public()
}
结论如下:
public | protected | default | private | |
---|---|---|---|---|
同包同类 | ✓ | ✓ | ✓ | ✓ |
同包不同类 | ✓ | ✓ | ✓ | - |
同包不同类继承 | ✓ | ✓ | ✓ | - |
不同包继承 | ✓ | ✓ | - | - |
不同包无任何关系的类 | ✓ | - | - | - |
3 I/O
3.1 File
File类包含了获得一个文件/目录的属性,以及对文件/目录进行改名和删除的方法。
文件名是一个字符串。File类是文件名及其目录路径的一个包装类。
注:该节示例省略了对异常的处理
对文件的操作
/* 如果跨平台, 建议使用f3的形式 */File f1 = new File("E:/test.txt");File f2 = new File("E:\\test.txt");// File.separator属性 => 获取当前操作系统的路径分隔符File f3 = new File("E:" + File.separator + "test.txt");/* 常用方法 */System.out.println("文件是否可读: " + f1.canRead());System.out.println("文件是否可写: " + f1.canWrite());System.out.println("文件的名字: " + f1.getName());System.out.println("上级目录: " + f1.getParent());System.out.println("是否是目录: " + f1.isDirectory());System.out.println("是否是文件: " + f1.isFile());System.out.println("是否隐藏: " + f1.isHidden());System.out.println("文件的大小: " + f1.length());System.out.println("是否存在: " + f1.exists());System.out.println(f1 == f2);System.out.println(f1.equals(f2));// 与路径相关System.out.println("f1绝对路径: " + f1.getAbsoluteFile());System.out.println("f1相对路径: " + f1.getPath());System.out.println("toString: " + f1.toString());File f4 = new File("demo.txt");if (!f4.exists()) {f4.createNewFile();}System.out.println("f4绝对路径: " + f4.getAbsoluteFile());System.out.println("f4相对路径: " + f4.getPath());System.out.println("toString: " + f4.toString());f4.delete();
对目录的操作
File f1 = new File("E:\\a");File f2 = new File("E:\\a\\b\\c");// 创建目录f1.mkdir(); // 创建单层目录f2.mkdirs(); // 创建多层目录// 删除目录 仅删除一层目录, 并且该目录下无文件(如果有文件, 则不会删除)f2.delete();// 查看String[] list = new File("E:/project/IdeaProjects").list();for (String s : list) {System.out.println(s);}File[] files = new File("E:/project/IdeaProjects").listFiles();for (File f : files) {System.out.println(f.getName());}
3.2 I/O流
File类可以非常方便地操作目录/文件,但用其获取文件/目录中的内容,似乎是不可行的。因此,Java提供了许多实现文件输入/输出的类。
注:I/O是Input/Output的缩写
SDK所提供的所有流类型位于包java.io内,其分别继承自以下四种抽象类型。
字节流 | 字符流 | |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
按照功能不同又可将流分为节点流和处理流。
3.2.1 FileReader & FileWriter
顾名思义,这一组是用于读/写文本文件的。何为文本文件呢?.txt、.java、.h、.c、.cpp、.py、.go、.js等等均为文本文件。而诸如.doc、.ppt、.jpg、.png、.mp3、.mp4、.avi等为非文本文件,而对于非文本文件的读/写操作,应使用字节流。
本节以一个.txt文件的复制操作为例。
FileReader fr = new FileReader(new File("E:/01.txt"));FileWriter fw = new FileWriter(new File("E:/02.txt"));int len = 0;char[] chars = new char[5];while ((len = fr.read(chars)) != -1) {fw.write(chars, 0, len);}fw.close();fr.close();
3.2.2 FileInputStream & FileOutputStream
FileInputStream fis = new FileInputStream(new File("E:/01.vsdx"));FileOutputStream fos = new FileOutputStream(new File("E:/02.vsdx"));int len = 0;byte[] bytes = new byte[520];while ((len = fis.read(bytes)) != -1) {fos.write(bytes, 0, len);}fos.close();fis.close();
4 对象的深拷贝
在实际编程过程中,往往需要考虑深拷贝的问题,如果类成员变量中含有其他类成员,则所含类成员也需要实现Cloneable接口。考虑一种极端情况,如果类中所有变量均为其他类的实例,那逐个为其实现Cloneable接口并不现实。
本节以设计模式中的原型模式(Prototype)为例。原型模式的目的是从原型实例克隆出新的实例,对于那些有非常复杂的初始化过程的对象或者是需要耗费大量资源的情况,原型模式是更好的选择。
火影忍者中的鸣人有一项秘术叫做“多重影分身之术”,每一个影分身相对自己来说是独立的,所以设计鸣人的类如下:
Naruto.java
package cn.edu.xtu;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;public class Naruto implements Cloneable, Serializable {private int x; // 鸣人在战场上的横坐标private int y = 0;public Naruto(int x) {this.x = x;}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void attack() {y++;}@Overridepublic Naruto clone() {try {ByteArrayOutputStream bout = new ByteArrayOutputStream();ObjectOutputStream out = new ObjectOutputStream(bout);out.writeObject(this);ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());ObjectInputStream in = new ObjectInputStream(bin);Naruto clone = (Naruto) in.readObject();return clone;} catch (Exception e) {e.printStackTrace();return null;}}
}
然后还要为其实现一个“产生鸣人的工厂”,即“多重影分身之术”。
NarutoFactory.java
package cn.edu.xtu;public class NarutoFactory {private static Naruto protoType = new Naruto(200);public static Naruto getInstance(int x) throws CloneNotSupportedException {Naruto clone = protoType.clone();clone.setX(x);return clone;}
}
当这两个类设计完之后,接下来就可以愉快的使用原型模式了。在主函数中,假设要创造500个鸣人,每个鸣人的横坐标满足集合 { x ∣ 0 ≤ x < 200 , x ∈ N } \{ x | 0 \leq x <200, x\in \mathbb{N}\} {x∣0≤x<200,x∈N}。
Exec.java
package cn.edu.xtu;import java.util.ArrayList;
import java.util.List;
import java.util.Random;public class Exec {public static void main(String[] args) throws CloneNotSupportedException {List<Naruto> narutoes = new ArrayList<>();for (int i = 0; i < 500; i++) {Naruto naruto = NarutoFactory.getInstance(new Random().nextInt(200));narutoes.add(naruto);}}
}
请重点观察Naruto重写的clone方法,Naruto类实现了Serializable及Cloneable接口,依此操作,即使后续Naruto中要添加通灵兽或尾兽这些实例,clone方法也无需进行修改。
5 反射
这篇关于Java SE痛点总结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!