begin:2018/10/17
参考文章:
eclipse不能查看源码
注:jdk源码在C:\Program Files\Java\jdk1.8.0_161\zip.rar
JAVA版本分类:
javaSE Java standard Edition 标准版
javaEE Java enterpaise Edition 企业版
javaME Java Micro Edition 微型版(消亡,被安卓取代)
java特点:
核心:跨平台,比如int永远32位
安全、面对、简单(入门)、高性能、分布式、多线程、健壮性
运行机制:
编译和解释结合,将java程序编译为字节码,然后通过jvm与底层连接
JVM、JRE、JDK的区别:
JVM(java virtual machine):虚拟机,用于执行字节码
JRE(java runtime environment) :包含java虚拟机、库函数、运行java应用所必须的文件
JDK(java development kit):包含JRE,以及增加编译器和调试器等用于程序开发的文件
java环境配置:
百度,用eclips开发
java程序实例:
Welcome程序:
public class Welcome{
public statitc void main(String[] args){
System.out.println("hard working!");
}
}
//保存:Welcome.java
//运行:javac Welcome.java
java Welcome
- 每个语句必须以分号结束,回车不是语句结束标志
- 一个文件可以有多个类,但只能有一个public
第一个桌球小项目:(源代码运行起来有问题,可能跟系统有关,先体会怎么编程)
import java.awt.*;
import javax.swing.*;
public class BallGame2 extends JFrame {
Image ball = Toolkit.getDefaultToolkit().getImage("image/ball.png");
Image desk = Toolkit.getDefaultToolkit().getImage("image/desk.png");
double x = 100;//ball横坐标;
double y = 100;//ball纵坐标;
double degree = 3.14/3; //弧度,指60度
//画窗口的方法;
public void paint(Graphics g) {
System.out.println("窗口被画了一次");
g.drawImage(desk, 0, 0, null);
g.drawImage(ball, (int)x, (int)y, null);//强制类型转换;
x = x + 10*Math.cos(degree);
y = y + 10*Math.cos(degree);
if(y > 500 || y < 80) {
degree = -degree;
}
if(x < 0 || x > 856) {
degree = 3.14 - degree;
}
}
//窗口加载;
void launchFrame() {
setSize(856,500);
setLocation(50,50);
setVisible(true);
//重画窗口;
while(true) {
repaint();//调用paint;
try {
Thread.sleep(40);
}catch(Exception e) {
e.printStackTrace();
}
}
}
//main 程序执行入口
public static void main(String[] args) {
System.out.println("寓教于乐");
BallGame2 game = new BallGame2();
game.launchFrame();
}
}
- 类起名,首字母大写 Man 、GoodMan
- 方法和变量,第一个单词小写,第二个首字母大写“驼峰原则”
- 变量的本质是一个“可操作的存储空间”
局部变量,从属于方法
成员变量,从属于对象
静态变量(static修饰),从属于类
第二个小代码:Student类
public class Student {
String name;//属性,只有属性的类叫做结构体stucture;
int age;
String school;
Computer comp;//外部类;
void myself() { //方法;
System.out.println("我是:"+ name);
}
void study() {
System.out.println("我在使用电脑: "+comp.brand);
}
public static void main(String[] args) {
Student stu = new Student();
stu.name = "pingan";
stu.age = 23;
stu.school = "nupt";
Computer c1 = new Computer();
c1.brand = "MAC";
stu.comp = c1; //Computer对象赋值给stu;
stu.myself();
stu.study();
}
}
//要定义在Student外部;
class Computer{
String brand;
}
/**输出:
我是:pingan
我在使用电脑: MAC
JVM内存模型
栈:
- 栈描述的是方法执行的内存模型,每个方法被调用都会创建一个栈帧(存储局部变量、操作数、方法出口等)
- JVM为每个线程创建一个栈,用于存放该线程执行方法的信息(实际参数、局部变量等)
- 栈属于线程私有,不能实现线程间共享
- 先进后出
- 系统自动分配。速度快,是一个连续的内存空间
堆:
- 用于存储创建好的的对象(new)
- JVM只有一个堆,被所有线程共享
- 不连续的空间,分配灵活,速度慢
方法区:
- JVM只有一个方法区,被所有线程共享
- 实际上也是堆,只是用于存储类、常量相关的信息
- 用来存储程序中永远不变或者唯一的内容(类信息、class对象、静态变量、字符串常量等)
画Student类的内存模型:
static关键字:
用static修饰的成员变量/方法叫静态成员变量/方法,也叫类变量/方法,其生命周期和类相同。静态变量/方法都存放在方法区中
也就是说,Java中的 static 关键字主要是用来做内存管理的。
super关键字:
用super访问父类被子类覆盖的属性或方法
super()永远位于构造器的第一句(默认)-继承树追溯,就是说子类必须实现父类的方法。Child–>Father–>Object
封装:
javaBean原则:
- 属性一律private;
- 提供相应的获取和改造属性的方法,如setName,getName(权限为public)
public void setName(String name){
this.name = name;
}
public void getName(String name){
return this.name;
}
多态:
子类重写父类的方法:
public class PolyTest {
public static void main(String[] args) {
Animal A = new Animal();
A.shout();
Dog D = new Dog();
D.shout();
Cat C = new Cat();
C.shout();
}
}
class Animal{ //class 后面没有()啊!!!!
public void shout() {
System.out.println("sing a song");
}
}
class Cat extends Animal{
public void shout() {
System.out.println("miao");
}
}
class Dog extends Animal{
public void shout() {
System.out.println("wang");
}
}
对象的转型:
可以向上转型,用的时候可以强制转回来,但是不同类型的对象不能强制转型
Animal d = new Dog(); //Dog转为Animal,可以想上转型;
Dog d2 = (Dog)d//强制转回来;
Animal d = new Cat(); //Cat转为Animal,可以想上转型;
Dog d3 = (Dog)d//强制转为Dog,编译器会报错,java.lang.ClassCastException;
final关键字:
- 修饰变量:不可改变
- 修饰方法:可被重载,但不可被子类重写
- 修饰类:不可被继承,比如Math、String等
多态的内存分析
注意点:
- 最开始的时候,java Test,这个Test的类也要写在方法区
- 方法区是加载类的代码、静态变量/方法、字符串常量的
- new创建cat时候,因为是多态继承的,所以要写出Cat–>Animal–>Object的框
- this 指向对象,就是最外层包围的
public static void main(String[] args){
Animal a = new Cat();
Cat a2 = (Cat)a;
testAnimalVoice(Voice(a));
}
抽象类(abstract class)
为什么需要抽象类:
- 是一种模板模式,为所有的子类提供一个通用模板,子类在此基础上进行扩展
- 避免了子类设计的随意性
要点:
- 有抽象方法的类只能定义为抽象类(abstract方法,然后必须在class前面也加abstract)
- 不能实例化,就是不能new了
- 可以包含属性、方法、构造方法
- 只能用来继承
- 必须被子类实现
- 抽象类里面可以包含非抽象方法
- 在类的非抽象方法里可以包含抽象方法,因为this.方法,这个this指向的是子类已经被实现的抽象方法
接口(interface)
- 比抽象类更抽象,不能包含非抽象类
- public static final 常量定义,默认
- public abstract 定义方法,默认
- 接口支持多继承
public interface MyInterface(){
/*public static final 常量定义,默认*/ String NAME = "boss”;
int MAX_NUMBER = 123;
//方法必须私有;
/*public abstract*/public void test();
public int test01(int a,int b);
public class Cat implements Animal{}
//多继承
public interface C extends A,B{}
回调(CallBack、Hook)
将代码的某一部分分离出来,在其他的地方再加上一些东西嵌入进去
package cn.nupt;
public class Test {
public static void drawFrame(Myframe f) {
System.out.println("1");
System.out.println("2");
System.out.println("3");
System.out.println("4");
f.say();
System.out.println("5");
System.out.println("6");
System.out.println("7");
}
public static void main(String[] args) {
drawFrame(new Frame01());
}
}
class Frame01 extends Myframe {
public void say() {
System.out.println("Frame01");
}
}
class Frame02 extends Myframe {
public void say() {
System.out.println("Frame02");
}
}
public abstract class Myframe {
public void say ();
}
内部类(innerclass)
作用:
- 提供更好的封装,可以让外部类直接访问,不允许同一个包中的其他类直接访问
- 内部类可以直接访问外部类的私有属性,外部类不能访问内部类的内部属性(“脸”不能呼吸,只能“鼻子”来呼吸,不能“脸.呼吸”,只能“脸.鼻子.呼吸”)
- 静态成员不能访问非静态成员(静态从属于类,非静态从属于对象)
- 非静态成员不能有静态属性/方法/初始化块
分类:
- 成员内部类:非静态内部类/静态内部类
- 匿名内部类:new 父类构造器(实参列表)实现接口(){}(适合只需要使用一次的类)
StringBuilder 和StringBuffer
String:不可变字符串
StringBuilder 和StringBuffer:可变字符串(主要用StringBuilder )
ArrayList类详解
ArrayList就是动态数组
容器Collection类
分类:
list:有序,可重复
ArrayList:底层实现是数组 、线程不安全,效率高,查询快,修改,插入、删除慢
LinkList:底层实现是链表,线程不安全,效率高,查询慢,修改、插入、删除快
Vector 线程不安全,效率低
set:无序,不可重复
map:键值对
java网络编程:
UDP编程
java异常
try-catch-finally
throws/throw
IO流
分类:
- 字节流:0-255整数,数字数据、可执行的程序、internet通信、字节码
- 字符流:只能处理文本数据
步骤:
- 创建一个与数据源或数据目的地相关联的流
- 将一个过滤器和流关联起来
- 通过过滤器(而不是流)来传输
相关异常:
FileNotFoundException/EOFException extends IOException
字节流相关类:
FileInputStream/FileOutputStream extends InputStream //主要用到
DataInputStream/DataOutputStream extends InputStream //好像没怎么用
文件流:构造函数:FileInputStream(String)里面写上文件名,
比如:
FileInputStream file = new FileInputStream("D:\\data\\test.py")
也可以用File类的属性separator 就是分隔符,不区分系统
char sep = File.separator;
FileInputStream("D:" + sep +"data" + sep + "test.py")
注:try(){}---catch--finally [try中的()有什么用?](https://blog.csdn.net/llkoio/article/details/78939148?utm_source=blogxgwz0)
try(){ //此处的try(){}括号中的一般是资源申请,实现了implement closeable 的类,就不用再加finally了,自动.close/.
}catch(IOException e){
}finally{
}
来一个小列子:读取一个图片
package cn.wuxi;
import java.io.FileInputStream;
import java.io.IOException;
public class IoStreamTest {
public static void main(String[] args) {
try(FileInputStream file = new FileInputStream("C:\\Users\\pingan\\Pictures\\Saved Pictures\\112.jpg"))
{ boolean eof = true;
int count = 0;
while(eof) {
int a = file.read();
System.out.println(a + " //");
////////////////////////////////
if(a == -1)
eof = false;
else
count ++;
}
System.out.println(count );
file.close();
}catch(IOException e ) {
System.out.println(e.toString());
}
}
}
再尝试将FileInputStream 对象read后用FileOuputStream write写入
package cn.wuxi;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class IoStreamTest {
public static void main(String[] args) {
try(
FileInputStream filein = new FileInputStream("C:\\Users\\pingan\\Pictures\\Saved Pictures\\112.jpg");
FileOutputStream fileout = new FileOutputStream("C:\\Users\\pingan\\Pictures\\Saved Pictures\\114.jpg")) {
boolean eof = true ;
while (eof) {
int a = filein.read();
fileout.write(a) ;
if(a == -1)
eof = false;
}
filein.close(); //是在try - catch 之间;
fileout.close();
} catch (IOException e) {
System.out.println(e.toString());
}
}
}
为什么read方法返回的是int,而不是byte?
答:在用输入流读取一个byte数据时,有时会出现连续8个1的情况,这个值在计算机内部表示-1,正 好符合了流结束标记。所以为了避免流操作数据提前结束,将读到的字节进行int类型的扩展。保留该字节数据的同时,前面都补0,避免出现-1的情况。
字符流:
字符流相关类:
FileReader extends InputStreamReader
具体操作和字节流一样
序列化和反序列化的概念
- 把对象转换为字节序列的过程称为对象的序列化。
- 把字节序列恢复为对象的过程称为对象的反序列化。
对象的序列化主要有两种用途:
1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
2) 在网络上传送对象的字节序列。
在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。
当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。
也就是说,一方面我们要将数据永远存储到硬盘上,另一方面是将对象 序列化传输,将数据表示为对象,而不是之前的外部格式,每次用到都要转化为 类可以使用的格式
序列化需要实现相关接口:
Serializable 不包含任何必须实现的方法,唯一用途是:指出类对象可以以串行方式存储和检索
对象通过类ObjectOutputStream的writeObject方法写入到流中
对象通过类ObjectIntputStream的readObject方法将对象从序列中读出
//序列化对象
ObjectOutputStream oo == new ObjectOutputStream(new FileOutputStream(new File("E:/Person.txt")));
oo.writeObject(需要序列化的对象);
//反序列化对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("E:/Person.txt")));
Person person = (Person) ois.readObject();//将文件中的序列变成对象,强制转换