Java 编程思想
安装编程环境
jdk下载链接
Eclipse下载链接
一、对象导论
1、 抽象机制
1.1 抽象过程
所有编程语言都提供抽象机制。汇编语言是对机器指令的抽象,高级语言是对汇编语言的一种抽象。但它们抽象出来的东西还是基于计算机的一下东西,和问题没有直接关联。而面向对象是直接对问题的抽象。
对象:问题空间中的元素及其在空间中的表示。
面向对象的实质:程序可以通过添加新类型的对象使自身适应问题。OOP允许根据问题描述问题,而不是根据计算机描述问题。
Java语言五个基本特性:
- 万物皆对象
- 程序是对象的几何,通过发送消息告诉彼此要做的
- 每个对象都有自己的由其他对象构成的存储
- 每个对象都有其类型
- 某一特定类型的所有对象都可以接受相同的信息
1.2 每个对象都有接口
接口对应了某一特定对象所能发出的请求。但是,在程序中,不许有实现这些请求的代码,于是就有了实现。每一个请求都有方法与之关联。
1.3 每个对象都提供服务
当试图开发或者理解一个程序设计时,最好的办法时把对象想象成“服务提供者”。
1.4 被隐藏的具体实现
将程序开发人员按角色分为类创建者和客户端程序员是大有裨益的。类的创建者构建类,只把必须的部分暴露给客户端程序员。于是有了访问控制权限,它存在的原因:
- 让客户端程序员无法触及它们不该触及的部分
- 允许库的设计者改变类内部的工作环境而不必担心会影响到客户端程序员
1.5 复用和继承
组合:把多个类融入进一个类。它经常被是为"has
a"(拥有)关系,比如汽车拥有引擎。继承没有组合的灵活性,因为编译器会给继承施加限制。在建立新类的时候,应该首先考虑组合。
1.6 继承
基本思想:如果我们可以以现有的类为基础,复制它,然后通过添加和修改这个副本创建新类就好多了。
导出类和基类有相同的类型。通过继承产生的类型等价性是理解面向对象程序设计方法内涵的重要门槛。
1.6.1 是一个和像是一个的关系
类与导出类是is-a(是一个)关系。比如圆形是一个几何形状。
有时候必须在导出类型里添加新的接口(扩展接口)。这个新的类型可以替代基类,但是这种替代不完美,因为积累无法访问新添加的方法。这种情况我们描述为is-like-a(像是一个)关系。比如热力泵像是一个空调
1.7 多态
在处理层次结构时,经常把对象当成基类来看待。比如几何形状有很多子类。于是存在一个问题,如果要让几何形状绘制自己,编译器不知道要执行哪一段代码,对象自身会依据自己的类型执行恰当的代码。
所以:编译器不肯产生传统意义上的函数调用,在OOP中,直到程序运行时才能确定代码的地址。
“你是一个Shape,我知道你可以erase()和draw()自己,那么去做吧,但是要注意细节的正确性”
1.8 单继承结构
所有的类都有一个超级基类:Object。它使得垃圾回收(内存管理)和异常处理变得容易很多
1.9 容器
开始的时候不知到会有多少个元素再里面,元素是可变的。如ArrayList,LinkedList
二、一切皆对象
2.1 用引用操纵对象
Java 建立的对象,拿到的是一个对象的一个引用,传递的也是对象的引用
2.2 存储
Java的所有对象存放到堆里
2.2.2 特例:基本类型
基本类型是存放于堆栈当中。boolean,char ,int ,double
....。基本类型具有包装容器类,比如
1 2
| char c = 'x'; Character ch = new Character(c);
|
它们还可以互相转换
高精度数字
BigInteger和BigDecimal类。
2.2.3 Java的数组
创建数组对象的时候,创建的是一个引用数组,并且每个引用都会初始化成null。
2.7 第一个Java程序
1 2 3 4 5
| public static void main(String[] args) { System.getProperties().list(System.out); System.out.println(System.getProperty("user.name")); System.out.println(System.getProperty("java.library.path")); }
|
2.8 注释和嵌入式文档
javadoc可以提取注释中的文档。它只能出现在/**
*/当中。可以使用独立文档标签@开头的东西。但是它会忽略掉private关键字的注释。
Java基础语法
foreach循环
可以用下面的for循环来遍历ArrayList
1 2
| for (Integer i : l1) System.out.println(i);
|
字符串转换数字
1 2 3
| String str = "1232"; int a = Integer.parseInt(str); double b = Double.parseDouble(str);
|
随机数
1 2 3 4
| Random rand = new Random(); for (int j = 0; j < 20; j++) { System.out.println(rand.nextInt(20)); }
|
转换成二进制数
1 2
| int a = 7; System.out.println(Integer.toBinaryString(a));
|
无符号位移>>>
带标签的流程控制
1 2 3 4 5 6 7 8 9
| label1: for (int i = 0; i < 999; i++) { System.out.println("ggg");
for (int j = 0; j < 999; j++) { System.out.println("hhh"); break label1; } }
|
### 值传递和引用传递
Java中的参数传参都是值传递,也就是复制一个副本传进去。如果是数组,对象的引用,就是复制一个引用传进去
1 2 3 4 5 6 7 8
| static void swap(int[] arr) { int a = arr[0]; arr[0] = arr[1]; arr[1] = a; arr = new int[]{3,44}; }
|
由于值传递,不能写swap函数修改2个变量,但是却可以交换数组的值。
上面的函数不能从新new一个数组,但是却可以修改里面的值,因为引用被复制了,可以通过计算修改对应地址的值,却不能重新定义它。
控制台输入输出
Scanner输入
1 2 3 4 5
| Scanner scan = new Scanner(System.in); str = scan.nextLine(); a = scan.nextInt(); double doub = scan.nextDouble(); long ll = scan.nextLong();
|
println输出
1
| System.out.println(str);
|
JAVA多态
类的类型
静态类型:定义时候左边的类型
动态类型:定义时候右边的类型
1 2
| A a = new A(); A a2 = new B();
|
调用规则:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| static class A { void f(A a) { System.out.println("A.A"); } void f(B b) { System.out.println("A.B"); } } static class B extends A { } public static void main(String[] args) { A a = new A(); A a2 = new B(); A a3 = new B(); a.f(a2); a3.f(a2); }
|
- 然后运行的时候去动态类型里找对应的方法,
如果没有则运行静态类型的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| static class A { void f(A a) { System.out.println("A.A"); } void f(B b) { System.out.println("A.B"); } } static class B extends A { void f(A a) { System.out.println("B.A"); } void f(B b) { System.out.println("B.B"); } } public static void main(String[] args) { A a = new A(); A a2 = new B(); A a3 = new B(); a2.f(a3); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| static class A { int a = 3; void f(A a) { System.out.println("A.A"); System.out.println(a.a); } } static class B extends A { int a = 5; void f(A a) { System.out.println("B.A"); System.out.println(this.a); } void f(B b) { System.out.println("B.B"); } } public static void main(String[] args) { A a = new A(); A a2 = new B(); A a3 = new B(); B b = new B(); a2.f(b); }
|
JAVA容器和实用类
ArrayList
1 2 3 4 5 6 7 8 9 10 11
| import java.util.ArrayList; import java.util.List;
List<Integer> l1 = new ArrayList<>(); l1.add(1); l1.add(-2); l1.add(9); l1.get(0); l1.addAll(l2); l1.size(); l1.isEmpty(); l1.contains(2); l.remove(4);
|
HashMap
1 2 3 4
| Map<Integer,Integer> map = new HashMap<>(), map2 = new HashMap<>(); map.put(key, value); map.get(key); map.putAll(map2);
|
高精度BigInteger
1 2 3 4 5 6 7 8
| BigInteger bga = new BigInteger("123"); a = bga.intValue(); bga.multiply(bga); bga.subtract(bga); bga = bga.add(bga); bga.divide(bga); bga.mod(new BigInteger("3")); bga.compareTo(new BigInteger("333"));
|
Iterator迭代器
迭代器需要实现2个方法:hasNext()和next()。JAVA的容器里都由对应的迭代器方法.iterator
1 2
| List<Integer> l1 = new ArrayList<>(); Iterator<Integer> lter = l1.iterator();
|
递归使用迭代器
如果需要递归使用迭代器,可以用subiterator来定义一个子迭代器来实现递归的操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public Iterator<File> iterator() { return new Iterator<File>() { int index = -1; Iterator<File> subIterator;
@Override public boolean hasNext() { if (files == null || index == files.size()) { return false; } return true; } @Override public File next() { if (index == -1) { index++; return Directory.this; } else if (index == files.size()) { throw new NoSuchElementException(); } if (subIterator == null) { subIterator = files.get(index).iterator(); } File ret = subIterator.next(); if (!subIterator.hasNext()) { subIterator = null; index++; } return ret; } }; }
|
或者可以模拟栈来实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public Iterator<FSElement> iterator() { return new FSIterator(this); }
private class FSIterator implements Iterator<FSElement> { private List<FSElement> toDo;
public FSIterator(FSElement root) { toDo = new LinkedList<>(); toDo.add(root); }
public boolean hasNext() { return !toDo.isEmpty(); }
public FSElement next() { if (toDo.isEmpty()) throw new NoSuchElementException(); FSElement next = toDo.remove(0); if (next instanceof Folder) { Folder f = (Folder) next; for (FSElement subitem : f.getChildren()) toDo.add(subitem); } return next; } }
|
Stream
lamda表达式的使用条件
- 接口中只有1个方法
- 默认实现方法除外
- Object类对应方法除外
满足上述条件的接口是函数式接口可以在前面加上 @FunctionalInterface 来检查
1 2 3 4 5 6 7
| @FunctionalInterface public interface MyRunnable extends Runnable { public abstract boolean equals(Object obj); default void add() { } }
|
lamda表达式调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public static void say(myInterface myInterface) { System.out.println(myInterface.sayHello("fyind", "hello world")); }
public interface myInterface { String sayHello(String name, String message); }
static String sayHello(String name, String message) { return name + message; }
String sayHello2(String name, String message) { return name + message; }
say((n, m) -> n+m); say((String n, String m) -> n+m); say((n,m) -> { return n + m; }); say(MyStream::sayHello); say(new MyStream()::sayHello2); say(String::concat);
myInterface m = String::concat; say(m);
|
(n, m) 是声明对象, 然后->
后面写方法的实现。关于调用也有很多不同的写法
流的基本知识
1 2 3 4 5 6
| graph LR id(数据源) ==生成流==> 过滤 subgraph pipeline 过滤-->排序 --> 采集 end 采集 ==生成结果 ==> id2(结果数据)
|
流的特性
1、不改变数据
2、不存储数据
3、不可重复使用
流的操作方式
1、中值操作 (惰性操作)
2、终值操作只会有一个(采集操作)
中值操作可以有多个,终值操作只能有一个
判断终值和中值
返回值是stream是中值操作,否则是终值操作
1 2
| l1.stream().peek(a -> System.out.println(a)); l1.stream().peek(a -> System.out.println(a)).collect(Collectors.toList());
|
流的操作顺序
按照数据进行拆分,一个一个排队执行,不是从左到右一起执行。是小数据一个一个流。
流的生成
1. 数组变成流
Stream.of(arr) 方法可以把一个数组变成流
Arrays.stream(arr) 也可以实现相同的功能
1 2 3
| String[] arr = { "ma", "zhi", "chu", "is", "java", "developer", "family" }; Stream<String> stream = Stream.of(arr); Arrays.stream(arr);
|
1 2
| Stream.of("a", "b", "c").forEach(System.out::println); Stream.iterate(0, a -> a+1).limit(10).forEach(System.out::println);
|
流的操作
1、peek 遍历(例子见上)
2、collect收集(例子见上)
1
| .collect(Collectors.toList());
|
3、limit 限制流的长度
4、forEach 对于每个生产的数
5、fliter 过滤
6、sorted排序
元素本身继承Comparable接口,通常是默认从小到大排序,使用Comparator.reverseOrder()可以倒序
1 2 3 4
| String[] stra = new String[]{"ttsd","abd", "dk", "ddss", "kdk"};
Stream.of(12,2,1,5,13,6).sorted().forEach(System.out::println); Arrays.stream(stra).sorted(Comparator.reverseOrder()).forEach(System.out::println);
|
按类中某关键字排序,该关键子必须由Comparable属性
1 2 3 4
| List<User> ascUsers = users.stream().sorted(Comparator.comparing(User :: getAge)).collect(Collectors.toList());
List<User> descUsers = users.stream().sorted(Comparator.comparing(User :: getAge).reversed()).collect(Collectors.toList());
|
实现Comparable接口
1 2 3 4 5
| .sorted((p1, p2) -> { if (p1.getDistance() > p2.getDistance()) return 1; else if (p1.getDistance() < p2.getDistance()) return -1; else return 0; });
|
文件操作
文件操作主要是由Path和File两个类和其中的方法完成的
创建文件
1 2
| Path pt = Path.of("test.class"); File f = pt.toFile();
|
常用函数
获得文件名
判断一个路径是文件还是文件夹
1 2 3
| Files.isDirectory(pth) Files.isRegularFile(pth) Files.exists(pth)
|
读取文本文件中的内容
1
| List<String> lines = Files.readAllLines(file);
|
遍历目录下所有文件
1 2 3 4
| Stream<Path> st = Files.walk(directory); st.map(Path::getFileName).forEach(System.out::println);
Stream<Path> st = Files.list(directory);
|
多线程
继承Thread类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class myThread extends Thread { public void run() { } }
myThread th = new myThread(); th.start();
try { th.join(); } catch (InterruptedException e) { e.printStackTrace(); }
|
同步
同步函数
1 2 3
| synchronized public void calc() { }
|
同步代码块
1 2 3
| synchronized(this) { }
|
网络编程
客户端
创建客户端
1 2 3 4 5 6 7 8 9 10
| private Socket socket; private int port;
try { socket = new Socket(server, port); } catch (Exception e) { return false; }
|
服务器
1 2 3 4 5 6 7 8 9 10 11 12 13
| private ServerSocket server; private int port;
try { server = new ServerSocket(port); } catch (IOException e) { e.printStackTrace(); }
Socket s = server.accept();
|
交互操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| private DataInputStream dis; private DataOutputStream dos;
private String read() throws IOException { String tp = ""; tp = dis.readUTF(); return tp; }
private void write(String msg) throws IOException { dos.writeUTF(msg); dos.flush(); }
dis = new DataInputStream(s.getInputStream()); dos = new DataOutputStream(s.getOutputStream());
|