java 面向对象基础学习

前面的忘记写了,算了就不发了

1.单例设计模式

1
2
3
4
5
6
7
8
9
public class test {
private static test test = new test();
private test(){
}
public static test get_object(){
return test;
}
}

在类里面完成这个类的构造,在类外面不能去创建对象,因为对象的构建方法是私有的,只能通过get_object这个类方法去获取这个对象

2.懒汉式单例

在第一次调用的时候创建一个对象,然后在后面的时候都使用这同一个对象

exp

1
2
3
4
5
6
7
8
9
10
public class test {
private static test test ;
private test(){
}
public static test getInstance(){
if (test==null){test=new test();System.out.println("创建对象");}
return test;
}
}

如果被频繁的使用,用单例,如果用的比较少,就可以用懒汉式单例

3.修饰符

image-20231128161903630

image-20231128163540451

4.继承

所有类都是object的子类

方法重写

image-20231128165443287

构造器

父类和子类都有构造器的情况下

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
package org.example;
import java.io.IOException;
import java.util.ArrayList;
import java.lang.*;
import java.util.Random;
import java.util.Scanner;


public class Main {
public static void main(String[] args){
b ccc=new b();
b cccc=new b("123");
}
}

class a {
public a(){
System.out.println("父类的无参数构造");
}
public a(String aa){
System.out.println("父类的有参数构造");
}
}
class b extends a{
public b(){
System.out.println("子类的无参数构造");
}
public b(String aa){
System.out.println("子类的有参数构造");
}
}

输出

1
2
3
4
父类的无参数构造
子类的无参数构造
父类的无参数构造
子类的有参数构造

先调用了父类的构造器,然后再次调用子类的构造器

假设父类的构造器只有特定参数的构造器,这样父类内默认没有无参数构造,就只调用子类的构造函数

super

子类的第一行都是super(),无论写不写都有,都会调用父类的构造器

如果父类没有相关参数的构造器,我们就要自己去写一个super去调用父类的构造方法

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
public class Main {
public static void main(String[] args){
b ccc=new b();
b cccc=new b("123");
}
}

class a {
// public a(){
// System.out.println("父类的无参数构造");
// }
public a(String aa){
System.out.println("父类的有参数构造");
}
}
class b extends a{
public b(){
super("123");
System.out.println("子类的无参数构造");
}
public b(String aa){
super("123");
System.out.println("子类的有参数构造");
}
}

这里父类是没有无参数构造的

这里使用super方法去调用父类的有参数构造,就不会报错,然后输出如下

1
2
3
4
父类的有参数构造
子类的无参数构造
父类的有参数构造
子类的有参数构造

就近原则

对象调用的时候取决于就近原则

5.多态

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
33
34
35
36
package org.example;
import java.io.IOException;
import java.util.ArrayList;
import java.lang.*;
import java.util.Random;
import java.util.Scanner;

public class Main {
public static void main(String[] args){
a test1 =new b();
a test2 = new c();
test1.run();
test2.run();


}
}

class a {
public void run(){
System.out.println("run");
}
}
class b extends a{
@Override
public void run() {
System.out.println("run pro max");
}
}
class c extends a{
@Override
public void run() {
System.out.println("run ultra");
}
}

都是a,但是在b和c 的状态下,调用的方法也不一样

对于方法,编译看左边,运行看右边

image-20231130100346814

在这里如果给abc都加上成员,再看看

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
33
34
35
36
37
38
39
40
package org.example;
import java.io.IOException;
import java.util.ArrayList;
import java.lang.*;
import java.util.Random;
import java.util.Scanner;

public class Main {
public static void main(String[] args){
a test1 =new b();
a test2 = new c();
test1.run();
test2.run();
System.out.println(test1.name);
System.out.println(test2.name);

}
}

class a {
public String name = "a";
public void run(){
System.out.println("run");
}
}
class b extends a{
public String name = "b";
@Override
public void run() {
System.out.println("run pro max");
}
}
class c extends a{
public String name = "c";
@Override
public void run() {
System.out.println("run ultra");
}
}

可以输出两次a

多态强调的是方法和行为的多态

而不是成员变量的,成员变量在开始的时候编译的是谁的就是用谁的

对于变量,编译运行都看左边

多态之后不能调用子类的特有方法,需要用特殊的方法

强制类型转换

如果需要使用子类的特有的方法可以使用强制类型转换去调用这个方法

如果直接这样

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
33
34
35
36
37
38
package org.example;
import java.io.IOException;
import java.util.ArrayList;
import java.lang.*;
import java.util.Random;
import java.util.Scanner;

public class Main {
public static void main(String[] args){
a test1 =new b();
test1.stop();
}
}

class a {
public String name = "a";
public void run(){
System.out.println("run");
}
}
class b extends a{
public String name = "b";
@Override
public void run() {
System.out.println("run pro max");
}
public void stop(){
System.out.println("stop!");
}
}
class c extends a{
public String name = "c";
@Override
public void run() {
System.out.println("run ultra");
}
}

这样调用会直接报错

但是如果强制类型转换就不会报错

1
2
b test2=(b) test1;
test2.stop();

直接转换可能会报错

instanceof

使用instanceof去判断t他的真实类型转换

1
2
3
if( a instanceof b ){
.....
}

6. final

修饰类 类就不能被继承了

修饰方法,方法是最终方法,也不能被重写了

修饰变量,变量只能被修饰一次

1
2
3
final int a = 1;
a =2 ;
//报错。不可以二次赋值

基本类型 的变量是不可以去修改的

引用性的变量不能修改地址但是可以修改地址所指向的值

static final

类似c里面的define 定义一个常量

需要大写加下划线构建

1
public static final String  a = "";

程序在编译的时候会直接进行宏替换,与原来的时候是一样的

7.抽象类

关键字 abstract

1
2
3
4
5
public abstract class abstr {
//这是一个抽象类
public abstract void eat();
//抽象方法,没有方法体,只有方法签名
}

image-20231203192153263

不能用来创建对象,需要被继承在之后再子类里面完善

8.模板方法模式

定义一个需要的模板方法

不清楚子类如何去完成,但是知道需要去完成

将需要子类修改的地方定义道抽象方法里面

需要完成的地方就让子类重写完成

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
33
34
35
36
37
38
package org.example;
import java.io.IOException;
import java.util.ArrayList;
import java.lang.*;
import java.util.Random;
import java.util.Scanner;

public class Main {
public static void main(String[] args){
b test1 =new b();
c test2 = new c();
test1.hello();
test2.hello();

}
}

abstract class a {
public abstract String run();
public void hello(){
System.out.println("hello");
System.out.println(run());
}
}
class b extends a{
@Override
public String run() {
return "b";
}

}
class c extends a{
@Override
public String run() {
return "c";
}
}

这里的定义了模板方法hello

然后将实现方法放到子类里面去

这里可以使用final去修饰模板方法,使得方法不能被重写

9.接口

image-20231204194023980

1
2
3
4
5
6
7
8
9
package org.example;

public interface A{
String SCHOOL_NAME="123";
//成员变量是常量
void test();
//默认是抽象方法
//接口是不能写构造器的
}

实现类必须要重写相关的函数

接口

1
2
3
4
5
6
7
8
9
10
package org.example;

public interface A{
String SCHOOL_NAME="123";
//成员变量是常量
void test();
//默认是抽象方法
//接口是不能写构造器的
//
}

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package org.example;
import java.io.IOException;
import java.util.ArrayList;
import java.lang.*;
import java.util.Random;
import java.util.Scanner;

public class Main {
public static void main(String[] args){
hello y = new hello();
y.test();

}
}
class hello implements A {//在这里实现了

@Override
public void test() {
System.out.println(SCHOOL_NAME);//在这里可以直接访问常量

}
}

如果实现了多个接口,就需要实现所有的方法

java只能单继承,却可以实现很多的接口,这里就完善了不能单继承的问题

默认方法

jdk8以上的新特点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package org.example;

public interface A{
String SCHOOL_NAME="123";
//成员变量是常量
void test();
//默认是抽象方法
//接口是不能写构造器的
//
default void test2(){
System.out.println("默认方法");
}//使用他的实现类去访问

}

可以定义默认方法

使用他的实现类去访问

privite方法

jdk版本大于9

1
2
3
private void test2(){
System.out.println("默认方法");
}

内部类去访问

静态方法

jdk版本大于9

1
2
3
static void test3(){
System.out.println("静态方法");
}//直接接口名字取访问就好了

接口内的方法默认是public的方法

image-20231204204009448

接口多继承

可以将一个接口继承多个和接口

实现一个一个类只需要一个接口实现就可以了

image-20231204204639421

方法的重载的时候,只根据函数签名去区分函数,而不是根据方法的返回值

10.内部类

1.内部成员类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package org.example;

public class car {
public class tnner{
private String name;
public static String school;
//内部类里面的静态类 jdk16以上支持
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}
}

创建这个类的对象的时候需要这样

1
car.tnner test = new car().new tnner();

调用这里的school

1
System.out.println(car.tnner.school);

假设在内部类里面有一个方法test可以调用

直接

1
2
car.tnner test = new car().new tnner();
test.test();

就可以直接调用这个函数

2.静态内部类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package org.example;

public class car {
public static class tnner{
private String name;
public static String school="123";
public void test(){
System.out.println("test");
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}
}

测试类

这里使用static修饰了这个方法

1
2
3
4
5
6
7
8
9
public class Main {
public static void main(String[] args){
System.out.println(car.tnner.school);//访问里面的静态参数
car.tnner test = new car.tnner();//创建这个类
test.test();//用函数

}
}

3.局部内部类

将类和接口直接写入其他类,方法

4.匿名内部类

特殊的局部内部类

不需要为这个类声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package org.example;
import java.io.IOException;
import java.util.ArrayList;
import java.lang.*;
import java.util.Random;
import java.util.Scanner;

public class Main {
public static void main(String[] args){
ctf web=new ctf(){
@Override
public void zuolao() {
System.out.println("web 坐牢");
}
};
web.zuolao();
}
}
abstract class ctf{
public abstract void zuolao();
}

这里创建了ctf这个抽象类,然后这里没有声明创建一个子类,但是这里的实际上的效果和子类一样

image-20231205152128290

作用举例

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
package org.example;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.ArrayList;
import java.lang.*;
import java.util.Random;
import java.util.Scanner;

public class Main {
public static void main(String[] args) {
JFrame win = new JFrame("hello_world");
JPanel panel= new JPanel();
win.add(panel);
JButton btn = new JButton("你好");
panel.add(btn);
panel.setSize(10,10);
win.setSize(400,400);
win.setLocationRelativeTo(null);
win.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
win.setVisible(true);
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {

}
});
}
}

这里的按钮事件监听器的时候,是使用了匿名内部类

11.枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package org.example;

public enum test {
a,b,c;
//第一个是枚举类的名字
private String name;

private test(){

}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

1
2
3
4
5
6
7
8
9
package org.example;

public class Main {
public static void main(String[] args) {
test a1=test.a;
System.out.println(a1);

}
}

image-20231206150657485

1
2
3
4
5
6
7
8
9
10
11
12
13
package org.example;

public class Main {
public static void main(String[] args) {
test a1=test.a;
System.out.println(a1.getName());
test a2=test.b;
test[] as = test.values();//获取所有的对象
test a3 = test.valueOf("c");//获取枚举的对象
System.out.println(a3.name());//获取对象的值
System.out.println(a3.ordinal());//获取对象的索引
}
}

抽象枚举类

构建对象的时候需要重写对象

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
package org.example;

public enum test {
a {
@Override
public void go() {

}
},b {
@Override
public void go() {

}
},c {
@Override
public void go() {

}
};
//第一个是枚举类的名字
private String name="123";
public abstract void go();
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

这里创建了一个抽象的方法,需要重写相关的方法之后才能行

单例枚举类

1
2
3
public enum C{
x;//这里就完成了一个单例类
}

这样的类的线程安全比较好

12.泛型

定义的时候使用了一个或者多个类型和类型,叫做泛型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package org.example;


import java.util.ArrayList;

public class Main {
public static void main(String[] args) {
ArrayList lixst=new ArrayList();
lixst.add("1");
lixst.add("2");
lixst.add(new String("123"));
for (int i = 0; i < lixst.size(); i++) {
System.out.println(lixst.get(i));
}
}
}

这里的ArrayList吗没有定义类型,就是一个泛型

如果使用<>去限制

在编译阶段能够帮助我们检查,同时约束了我们操作的类型

arraylist泛型原理

在arraylist源码里面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable

E elementData(int index) {
return (E) elementData[index];
}

/**
* Returns the element at the specified position in this list.
*
* @param index index of the element to return
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
rangeCheck(index);

return elementData(index);
}

在这里送入的类,会被添加到e里面,然后通过e去获得,调用相关的函数。将相关的类型作为参数添加到函数里面去了

泛型类

image-20231215163646722

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package org.example;

public class list <E>{
private Object[] arr = new Object[10];
private int size=0;
public boolean add(E e){
arr[size]=e;
size++;
return true;
}
public E get(int index){
return (E) arr[index];
}
}

用object去储存这些不同的类型,在需要的时候可以使用强制类型转换去获得

也可以定义多个类型

1
2
public class list <E,T>
//这里的e,t出传入什么就是什么

也可以用extend去限制某一个类的子类

1
public class list <E extend T>

泛型接口

image-20231215164922499

image-20231215165903579

13.map集合

map是一种双链数组

image-20231215213322466

image-20231215213518113

1
2
3
4
5
6
7
8
9
10
public class Main {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
map.put("a",1);
map.put("hello",23);
System.out.println(map);
//输出{a=1, hello=23}
}
}

对于hashmap,无序,不重复,无索引

如果后面有键名重复的数据,会覆盖前面的数据

linkedhashmao是有序,不重复的,无索引的

treemap默认排序,不重复,无索引

map常见的操作

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
package org.example;


import javax.print.DocFlavor;
import java.awt.image.ImageProducer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;


public class Main {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
map.put("a",1);
map.put("hello",23);
System.out.println(map);
System.out.println(map.get("a"));//通过键获得键值
System.out.println(map.size());//获得map中的多少
map.remove("hello");//删除键
System.out.println(map.containsKey("a"));//判断是否包含这个键
System.out.println(map.containsValue(2));//判断是否包含这个值
map.clear();//清空map
System.out.println(map.isEmpty());//判断是否为空
Set<String> key = map.keySet();//把所有的建全部放到set里面
Set<Integer> key1 = (Set<Integer>) map.values();//把所有的值全部放到map里面

}
}

putall方法可以把map1里面的全部内容copy一份到map1里面

map的遍历方式

1.获取键名然后获取键值

1
2
3
4
5
6
7
8
9
Map<String,Integer> map = new HashMap<>();
map.put("a",1);
map.put("hello",23);
map.put("web",1);
map.put("pwn",2);
Set<String> keys = map.keySet();
for (String key:keys) {
System.out.println(map.get(key));
}

使用set集合获取所有的键名,然后去遍历这个set集合,然后去获得这个key对应的值

2.将键值对作为一个整体去遍历

image-20231219183914272

1
2
3
4
Set<Map.Entry<String, Integer>> list=map.entrySet();
for (Map.Entry<String, Integer> entry:list){ System.out.println(entry.getKey()+"==>"+entry.getValue());
}

把map对象里面的封装成对象,然后放到一个list里面,然后直接读取就好了

3.使用lambda

jdkb1.8之后才能用

1
map.forEach((k,v)-> System.out.println(k+"==>"+v));

这里就可以直接遍历了

14.反射

加载类,将方法直接加载到内存里面,然会允许使用变成来解析类里面的成分

image-20231219191519135

获取这个class对象

1.类名字.class

1
Class c1=ctf.class;//获取对象

2.直接Classforname

1
Class c2 = Class.forName("org.example.ctf");//获取class对象

3.实例化对象然后调用getclass方法

1
2
ctf a = new ctf();
Class c3 =a.getClass();//获取class对象

获取构造器

image-20231220140810644

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
33
34
35
36
37
38
package org.example;


import javax.print.DocFlavor;
import java.awt.image.ImageProducer;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import static sun.plugin.util.ProgressMonitor.get;


public class Main {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class c1=ctf.class;//获取对象
// System.out.println(c1);
//定义一个构造器的数组
Constructor[] constructors=c1.getConstructors();
// constructors[0].getName();//获取构造器的名字
for (Constructor constructor:constructors) {
System.out.println(constructor.getName()+"==>"+constructor.getParameterCount());
}
}
}
class ctf{
String name = "web";
int age = 114;
public ctf(){
System.out.println("test1");
}
public ctf(String name){
System.out.println("test2");

}
}

获取特定的构造器

1
2
Constructor c2 = c1.getConstructor();//这里是构造器内的参数,这里没有参数,默认就是无参构造;
System.out.println(c2);
1
Constructor c2 = c1.getConstructor(String.class);

这里就获取的有参数的构造器

反射创建对象

image-20231220143335156

1
2
3
    Constructor c2 = c1.getConstructor();
// System.out.println(c2);
c2.newInstance();

这里调用无参数构造器

能够直接建立一个对象

1
ctf AsaL1n = (ctf) c2.newInstance();

也可以强制转换,禁止检查访问控制

1
2
c2.setAccessible(true);//禁止判断权限,强制暴力反射
ctf AsaL1n = (ctf) c2.newInstance();

获取类的成员对象和方法

image-20231220144508542

同构造器,这里不说了

使用filed去获取成员

获取成员类

image-20231220150128923

触发某一个方法

使用invoke方法

1
2
3
Class c1=ctf.class;//获取对象
Method m = c1.getMethod("hello");//获取方法
m.invoke(ctf.class.newInstance());//指定这个方法的对象,后面可以添加(如果有)方法的参数

反射可以破坏封装的完整性

接下来开始学习java web了 每天学点序列化链子啥的,要期末考拉