驴のJAVA——奇妙之旅

部分笔记来自韩顺平教育

Markdown快捷键

IDEA快捷键

1.删除行:Ctrl + D

2.复制行:Ctrl + Alt + 向下箭头

3.补全代码:Alt + /

4.导入该行需要的类:Alt + Enter

5.生成构造器快捷键:Alt + insert

6.快速定位方法Ctrl + B

7.自动分配变量名:.var

1.类与对象

1.对象的内存布局

)

举个例子:

1
Cat cat1 = new Cat();

​ cat1是一个引用类型,他指向一块内存地址,那块内存地址里有类的==属性信息==

但要注意的是,如果是字符串型的属性信息,会放在==方法区==中的==常量池==里,只在类的内存地址中保存一个字符串的地址(如图)。

​ 当Cat类被new时,同时会在方法区对类的信息进行一个加载,加载内容是==属性信息==和==方法==。

2.类与对象的内存分配机制

先看代码:

1
2
3
4
5
Person p1 = new Person();
p1.age = 10;
Person p2 = p1;
//p1.age = 20;
System.out.println("p2.age = " + p2.age);

当我们先new了一个对象p1,并给p1的属性赋了值,如果这时再将p1赋值给p2,并输出p2的属性,会出现什么:

1
p2.age = 10

和p1的值一致,那如果我们在输出之前修改p1的属性,结果这样:

1
p2.age = 20

这说明p1,p2指向了同一块内存地址,相当于p1,p2是一个人的两个名字,但都是指向该人。

(补充)JAVA的内存结构

Java内存结构分析:
  • 1.栈:存放基本数据类型(局部变量)
  • 2.堆:存放对象
  • 3.方法区:常量池(常量,比如字符串),类加载信息
Java创建对象流程的简单分析:
1
Person p1 = new Person();
  • 1.先加载类信息(属性,方法)==一个类只加载一次==
  • 2.在堆中分配空间,并默认初始化
  • 3.把空间的地址分配给p1,p1指向该地址
  • 4.进行指定初始化

2.JAVA方法调用机制

)

3.封装

步骤:

1)属性私有化

2)公共的get set方法,get用于获取,set用于赋值并判断其合理性

封装与构造器:可以在构造器内调用get,set,同样可以判断其合理性,如图

4.多态

向上转型

父类的引用指向子类的对象,例如:

1
2
Animal animal = new Dog();
//Dog是Animal类的子类

同时满足:**==编译类型看左边,运行类型看右边==**(可以调用父类所有成员(看权限),不能调用子类特有成员,因为调用是由编译类型决定的,调用方法时,先从子类开始找,如果有则运行子类的方法,特别是有方法重写的时候)

向下转型

如果用向上转型定义了一个对象,那就会出现无法调用子类特有对象的情况,如果要调用,则需要进行向下转型,我习惯于看做强制类型转换

1
2
3
Dog dog = (Dog) animal;
//animal.pop();这样是错误的,因为pop方法是Dog类特有
dog.pop();

动态绑定机制

简单说,只要调用了某个类的方法,那就会动态绑定到该类(用该类的属性)

多态数组

instanceof用于判断运行类型,然后就可以根据运行类型通过向下转型来调用特有方法

1
2
3
if(persons[i] instanceof Student){
((Student)person[i]).study();
}

动态参数

即如果方法内的参数类型为父类,调用时可以传入子类对象作为参数。

5.类变量类方法

类变量是指属于这个类的变量,被所有该类的对象所共有,所以是静态的

1
private static int n;

类方法是指一个被所有该类的对象共有的方法,它只能访问静态参数,另外静态方法可以实现类名.方法名()直接调用,不需要对象

1
public static void A();

6.代码块

定义:

代码块又称初始化块,属于类中的成员,类似与方法,将逻辑语句封装在方法体重,用{}包围,可以用做对象初始化

基本语法:

[修饰符]{//修饰符可写可不写,但要写只能写static

代码

};

使用细节:

1.静态代码块只执行一次,普通代码块一个对象一次

2.类何时被加载 ==重要==

1)创建对象

2)创建子类对象

3)使用静态成员

3.

先调用静态,在调用普通

4.

7.单例设计模式

解释:这个模式的类只允许有一个对象,称为单例,要符合这个要求,必须要把构造器==私有化==,这样用户就不能自己new对象了。

1
2
3
4
5
6
7
8
9
10
11
12
//例子(饿汉式)
class GirlFriend{
private String name;
private GirlFriend(String name){
this.name = name;
}
//构造器私有化
private static GirlFriend gf = new GirlFriend("xiaohong");//在类的内部实例化对象//这个对象一定是私有且静态的,不是静态的话我们的静态方法返回不了。
public static GirlFriend getGirlF(){
return gf;
}
}

懒汉式和饿汉式的区别在于,饿汉式是不管你用没用,他都创建一个对象等你,懒汉式是你不调用不创建。代码上的区别就在于,懒汉式把对象的创建放在了Get函数里。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Girl{//懒汉式
private String name;
private static Girl girl;
private Girl(String name){
this.name = name;
}
static Girl getGirl(String name){
if(girl == null){
girl = new Girl("某某某");
}
return girl;
}
}

8.final关键字

9.抽象类

10.内部类

局部内部类

匿名内部类

目的:简化开发,当某个类继承某个类,或者说一个接口,你只会使用它们一次,如果专门为他们写一个新的类或者接口,太过繁琐,我们就可以用匿名内部类实现。

1
2
3
4
5
6
7
8
9
10
//例子:
interface A{
void say();
}
A a = new A(){
void say(){
System.out.println("Hello World");
}
};//分号别忘了
a.say();
1
2
3
4
5
6
7
8
9
10
//抽象类不能实例化,但可以通过匿名内部类
abstract A{
abstract void say();

}
A a = new A(){
void say(){
//输出
}
};

==你甚至可以:==

1
2
3
4
5
new Person{
void say(){
//输出
}
}.say();//直接调用方法

成员内部类

1
2
3
4
5
6
7
8
class A{
int a;
class AA{//成员内部类
void say(){
//输出
}
}
}

外部类调用成员内部类的方法

1
2
//方法一
A.a 对象名 = A.new a();

法二:在外部类里提供返回内部类对象的方法,接受类型仍然是A.a

11.枚举类

1
2
3
4
5
6
7
//举例
enum Student{
XM("小明""18"),XH("小红"18);//一定放在第一排,多个用逗号间隔
String name;
int age;
//构造器,get,set省略
}

枚举类常用方法

增强==for循环==

1
2
3
for(int i : A){
//输出i
}

注意!只能遍历不能赋值,因为i是个临时变量,不改变原来的值。

12.集合

集合体系图

List常用方法

首先实现List接口的类,里面的元素是有序的,可重复的

遍历collection类的方法

法一:迭代器(**==快捷键:itit + 回车==**)

1
2
3
4
5
6
//假设有集合,名字为col
Iterator iterator = col.iterator();//获取该集合的迭代器
while(iterator.hasNext()){//括号里的用来判断下一个地址有无元素
Object next = iterator.next();//Object接受
//输出next
}

法二:增强for

1
2
3
for(Object obj:col){
//输出
}

ArrayList常用方法

set接口:无序,不能有重复的,可以存放null

13.应用过程如何选择集合类

collection类的一些工具

14.使用JUnit快捷测试代码

JUnit可以用来快速测试类方法,不用搞对象

1
2
3
4
@Test//在需要测试的方法前加这个,然后Alt + enter 导入包之类的
public void A(){
...
}

15.java作图

java坐标图

画板具体创建过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class myPaint extends JFrame{//继承了一个窗口
private myP mp = null;//画板类型
public static void main(String[] args) {
new myPaint();//画板对象
}

public myPaint(){
mp = new myP();//在构造器里对画板初始化
this.add(mp);//将画板加入窗口
this.setSize(300,300);//设置窗口大小
this.setVisible(true);//窗口可视化
}
}
class myP extends JPanel{//相当于一个画板类型
@Override
public void paint(Graphics g) {
super.paint(g);//g相当于一个画笔,提供了很多方法,可以作图
g.drawOval(20,20,100,100);
}
}

16.线程

实现线程的方法

1.继承Thread 重写run方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void main(String[] args) {
AoLG a = new AoLG();
a.start();//不是run
}
}
class AoLG extends Thread{
@Override
public void run() {
while(true){
System.out.println("加油,奥利给!");
try {
//快捷try-catch:ctrl + alt + t
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

}
}

2.实现Runable接口 重写run方法

1
2
3
4
5
6
7
8
9
10
11
main{
AOlg a = new AOlg();
Thread t = new Thread(a);//这个调用很重要
t.start();
}
class AOlg implements Runnable{
@Override
public void run() {

}
}

线程插队

线程名 . join();

注:插队本质是让调用插队函数的线程休眠,例如在main线程中调用子线程插队,则会休眠main让子线程先执行完。

守护线程

线程名 . setDaemon(true);

本线程结束,调用的子线程(守护进程)也结束

线程同步机制

同一时间内只能有一个线程对内存进行操作

实现方法:

synchronized关键字

1
public synchronized void m(){}

Java网络部分

1.IP地址

1.IPV4一共有32位,四个字节,每个字节8位,每个都能显示0~255之间的数

2.IP地址:唯一标识主机

InetAddress类

2.Socket介绍

简单讲就是一个桥梁,可以在两个网络之间进行IO流传递

3.TCP编程

字节型

思路:

==服务器端==代码:

==主机端==代码:

结束标志

用于表示写入结束,不加会导致程序不知道是否写入结束,会一直卡在那里

字符型

输出

读入

4.利用TCP实现文件上传

5.实现多线程文件上传

倘若要提高效率,可以调用线程,实现每访问一次就开一个线程

1
2
3
new Thread(new Runable){
重写run方法
}).start;

注意:1.服务端应该提前用死循环括起来,让他一直监听

2.文件名应该自定义一个生成模式,防止文件名重复

Java反射

1.获取类的class方法

1.类名 + class

1
Class<Student> s = Student.class;

2.调用对象的class方法

1
2
Student student = new Student();
Class<? extends Student> studentClass = student.getClass();

3.使用class类静态方法Class.forName(某个类的全路径)

1
Class<?> aClass = Class.forName("com.Lfs_code.Student");

2.通过反射获取class类的构造方法

1.获取单个构造方法

1
2
Constructor<Student> constructor = s.getConstructor();//无参
Constructor<?> constructor = aClass.getConstructor(int.class,String.class);//有参

注获取有参构造方法时,需要用到数据类型的“.class”形式

2.另外如果需要访问私有构造方法需要使用

1
2
3
Constructor<?> constructor = aClass.getDeclaredConstructor(int.class,String.class);//私有公有都能访问
//调用是必须提前设置访问权
constructor.setAccessible(true);

3.访问成员变量

1.获取全部成员变量,顺便遍历

1
2
3
4
5
Field[] declaredFields = aClass.getDeclaredFields();
for (Field f:declaredFields
) {
System.out.println(f);
}

2.获取单个成员变量,并修改

1
2
3
Field name = aClass.getDeclaredField("name");
name.setAccessible(true);//如果该变量是私有的,就设置它的访问权
name.set(o,"林峰");

4.反射获取成员方法

1.获取全部方法(和上面大差不差,基本不用)

2.获取单个方法

1
Method study = aClass.getMethod("study");

3.方法的调用

1
study.invoke(o);//方法类型 + invoke + (调用方法的对象)