JavaSE复习

JVM内存管理

内存管理:由JVM来管理的
-堆:
1.存储的是new出来的对象(包括成员变量)
2.垃圾:没有任何引用所指向的对象
3.垃圾回收器(GC)不定时到内存中清扫垃圾,回收过程是透明的(看不到的),
不一定发现垃圾就立刻回收,通过调用System.gc()可以建议JVM尽快调度GC回收
4.实例变量的声明周期:
-创建对象的时候存储在堆中,对象被回收时一并被回收
5.内存泄漏:
-不在使用的对象没有及时的回收,一直占用的内存,严重的内存泄漏会导致系统崩溃
-建议:不在使用的对象应及时将引用设置为null

-栈:
1.存储正在调用的方法中的局部变量(包括方法的参数)
2.调用方法时,会在栈中为该方法分配一块对应的栈帧 栈帧中存储局部变量(包括方法的参数),方法调用结束,
栈帧被自动清除,局部变量一并被清除
3.局部变量的声明周期:
调用方法时存储在栈中,方法结束时与栈帧一并被清除

-方法区:
1.存储.class字节码文件(包括静态变量、所有方法)
2.方法只有一份,通过this来区分具体的访问对象

API

常量池:
-java对字符串有一个优化措施:字符串常量池(在堆中)
-java推荐使用字面量(String s = “abc”)的方式来创建字符串,并且将那个字符串的引用存储在常量池中,当
我们使用相同字面量在创建时将复用常量池中的对象,以减少内存开销
字面量方式创建才会存储在常量池中
String str = “abc”; //字面量
String str2 = str + “123”; //字符串拼接,这种是不会被存储在常量池中的

常见面试题:
String s = new String(“hello”);
问:如上语句创建了几个对象?
答:两个
-第一个:字面量"hello"
–java会创建一个String对象表示字面量"hello",并将其存入常量池
-第二个:new String()
–new String()时会在创建一个字符串对象,内容是hello字符串的内容
s引用指向的是new String()这个对象的地址

包装类

包装类:
1.可以通过包装类来获取到基本类型的取值范围。

   int max = Integer.MAX_VALUE; //获取int最大值
    int min = Integer.MIN_VALUE; //获取int最小值

    long max = Long.MAX_VALUE; //获取long最大值
    long min = Long.MIN_VALUE; //获取long最小值

    2.包装类可以把字符串类型转换为对应的基本类型(该字符串正确表达了对应的基本类型的值)
    String str = "123";
    int num = Integer.parseInt(str); //将字符串str转换为int类型

    String str = "123.123";
    double dou = Double.parseDouble(str); //将字符串str转换为double类型

修饰符、接口、抽象类

修饰符权限:
public int a;------任何类
protected int b;—本类 子类 同包类
int c;-------------本类 同包类(java不建议使用默认权限)
private int d;-----本类

访问控制修饰符:
final:最终的,不可改变的
-修饰变量:变量不能被改变
-修饰方法:方法不能被重写
-修饰类:不能被继承

stetic final常量:
-由类名点调用,声明并且赋值,不能被改变
-所有字母都大写,由下划线分隔

class Boo{
    public static int num = 5;
    public static final int COUNT = 5;
}
// 先加载Boo类和num变量到方法区中,然后再方法区中获取到num的值然后输出
System.out.println(Boo.num);
// 编译器在编译时会将常量直接替换为具体的值,
效率高,等价于
System.out.println(Boo.COUNT); =  System.out.println(5);

成员变量分两种:
-实例变量:没有static修饰,属于对象,存在堆中,有几个对象就有几份,通过引用对象点来访问
-静态变量:由static修饰,属于类的,存在方法区,只有一份,通过类名点访问(所有对象共享这一份值)

static:静态的
-静态变量:由static修饰,属于类,存在方法去,只有一份
-静态方法:由static修饰,静态能访问静态,静态不能访问普通方法
-静态块:由static修饰,属于类,在类被加载期间自动执行
Demo class{
static{
System.out.println(“只会被加载一次”);
}
}

-类加载执行顺序
加载静态代码块然后再加载构造方法

抽象类:
-由abstract修饰
-包含抽象方法的类必须是抽象类
-抽象类不可以被实例化,子类要重写所有抽象方法,不写也可以继续抽象下去

成员内部类:应用率低
-类中套一个类
-内部类通常只服务于外部类,对外不具备
-内部列可以访问外部类所有成员,包括私有的
-内部类中有个隐式的引用指向创建它的外部类对象,外部类名.this

只要是类就会有自己的.class字节码文件
匿名内部类:
-在匿名内部类中不能修改外边的变量,如果外边修改过变量,则访问的权限都没有

接口:
-由interface定义
-接口理由抽象方法和默认方法,还有常量
public static final int NUM =5
public abstract void show();
接口里的都是public公开的
-接口不能被实例化,只能继承或有类去实现implements接口中所有的抽象方法
-类只能单继承,接口与接口之间能多继承,用逗号隔开
-一个类能实现多个接口,用逗号隔开
-如果继承和实现都需要,应先继承后实现
-接口是对类只能单继承局限性的扩展

多态:
-父类的类型指向子类的引用
-多态的前提是,有继承,多态是对方法的多态

类型强制转换
条件1:引用所指向的对象,就是该类型
条件2:引用所指向的对象,实现了该接口或继承了该类
   instanceof可以判断是否满足以上两个条件,满足为true
    System.out.println( o instanceof Boo); //true
    System.out.println( o instanceof Inter); //true
    System.out.println( o instanceof Coo); //false
    if ( o instanceof Boo){
        Boo o1 = (Boo)o;
    }
    Aoo o = new Boo();
    Boo o1 = (Boo)o; //符合条件1,o这个引用的对象就是该类型
    Inter o2 = (Inter)o; //符合条件2,o这个引用的类型实现了Inter这个接口
    Coo o3 = (Coo)o; // 运行错误,没有满足两个条件

    interface Inter {}
    class Aoo {}
    class Boo extends Aoo implements Inter {}
    class Coo extends Aoo {}

IO

java.io.File io: input输入 output输出
File可以表示硬盘上的一个文件或目录(实际表示的是一个抽象路径)
File可以:
1.访问其他表示的文件或目录的属性信息(名字,大小,修改时间等)
2.可以访问一个目录的子项内容
3.但是File不能访问文件数据

public class FileDemo {
    public static void main(String[] args) {
        /**
         * 实际开发中我们不会使用绝对路径,虽然清晰明了,但不利于跨平台
         * 相对路径有更好的跨平台性
         * ./在IDEA里表示的是当前项目所在的目录下
         */
       // File file = new File("D:/project/CGB/Java_/SE/demo.txt");
        File file = new File("./demo.txt");

        // 获取File表示的文件或目录的名字
        String name = file.getName();
        System.out.println("获取File文件或目录的名字:"+name);

        // 获取大小,就是文件在硬盘上实际占用的空间(单位字节)
        long length = file.length();
        System.out.println("大小: "+length+"字节");

        /**
         * write:写  read:读
         * hidden:隐藏
         */
        boolean cw = file.canWrite();
        System.out.println("可写"+cw);

        boolean cr = file.canRead();
        System.out.println("可读"+cr);

        boolean ih = file.isHidden();
        System.out.println("是否隐藏"+ih);
    }
}

删除文件

import java.io.File;
/**
 * 删除一个文件
 */
public class DeleteFile {
    public static void main(String[] args) {
        // ./不写也行,默认从  ./ 开始
        File file = new File("test.txt");
        if (file.exists()) {
            file.delete(); //将file表示的文件或目录删除
            System.out.println("该文件已删除!");
        } else {
            System.out.println("该文件不存在!");
        }
    }
}

新增一个文件

import java.io.File;
import java.io.IOException;

/**
 * 使用File新建一个文件
 */
public class CreateNewFile {
    public static void main(String[] args) throws IOException {

        /**
         * 创建文件的前提是该文件所在的目录必须存在,如果不存在会在创建是抛出异常
         * File file = new File("./mydir/test.txt");
         *
         */

        // 在当前目录项目下新建一个文件test.txt
        File file = new File("./test.txt");
        if (file.exists()) {
            //存在
            System.out.println("该文件已经存在");
        } else {
            //不存在
            file.createNewFile();
        }
    }
}

Java IO
java使用输入与输出的两个方向来规定读和写操作。
其中输入是从外界到我们写的程序的方向是获取的过程,是[读取]操作
而输出则是发送到外界的方向,是[写出操作]

Java将IO比喻为 "流" ,我们可以理解为是连接我们写的程序与外界设备之间的"管道",
类似现实生活中的水管,只不过这个管子里流的不是水,而是[字节]

java.io.InputStream和OutputStream是所有字节输入流与输出流的的超类,他们是抽象类
InputStream定义了读取字节的相关方法
OutputStream定义了写出字节的相关方法
实际开发中我们可以创建不同种类的输入与输出流来连接对应的设备(如网络、文件等)进行读写操作

文件流
java.io.FileInputStream和FileOutputStream,他们继承自InputStream和OutputStream是实际用于读写文件的流

在这里插入图片描述
在这里插入图片描述

复制
在这里插入图片描述上述读取为单字节读写;
通过提高每次读写的数据量,减少实际读写的次数,可以提高读写效率
单字节的读写属于随机读写形式。
一组字节的读写属于块读写形式。
大多数的硬块读写都比随机读写性能好,尤其机械硬盘上体现最为明显

InputStream和OutputStream上定义了块读写数据的相关方法
在这里插入图片描述
在这里插入图片描述
优化上述代码
在这里插入图片描述
字符串的写出
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

网络编程

TCP可靠传输协议,是一块一块数据发送的,如果上一块数据发送成功才会发送下一块数据,如果超过指定时间另一端没有接收成功,则会重复发送这一小块内容.谁发起请求谁是客户端,请求中需要携带一些信息,服务器才能返回数据(tcp协议规定)
在这里插入图片描述
scoket
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

聊天室项目

/**
    聊天室的客户端
 */
public class Client {
    /**
     * java.net.Socket
     * 封装了TCP协议的通讯细节,我们基于它就可以与远端计算机建立TCP连接,
     * 并基于一对输入与输出流的读写完成与远端计算机的数据交互操作。
     * 可以把Socket想象成"电话"
     */
    private Socket socket;

    /**
     * Socket的构造器:
     * Socket(String host, int port)
     * 参数1:要连接的远端计算机(服务器)的IP地址
     * 参数2:要连接的运行在远端计算机上的服务端应用程序开启的服务端口
     * 我们通过IP地址可以找到网络上的服务器计算机,通过端口可以连接到运行在该服务器计算机上的服务端应用程序
     *
     * 并且这个构造器实例化Socket的过程就是与服务端建立连接的过程,如果连接失败会抛出异常
     */
    public Client() {
        try {
            System.out.println("正在连接服务端...");
            socket = new Socket("localhost",8088);
            System.out.println("已连接服务端!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void start() {
        try {
            // 启动用于读取服务端发送过来消息的线程
            ServerHandler handler = new ServerHandler();
            Thread t = new Thread(handler);
            t.start();
            /**
             * Socket提供的方法:
             * OutputStream getOutputStream()
             * 通过socket获取一个字节数出流,使用该输出流写出的字节数据会发送给建立连接的远端计算机。
             * 而对方也可以通过建立连接的Socket获取输入流,读取到我们写出的字节
             */
            OutputStream out = socket.getOutputStream(); //通过该流写出的字节就发给了远端计算机
            OutputStreamWriter osw = new OutputStreamWriter(out, StandardCharsets.UTF_8);
            BufferedWriter bw = new BufferedWriter(osw);
            PrintWriter pw = new PrintWriter(bw,true);
            Scanner scanner = new Scanner(System.in);
            /**
             * 使用缓冲字符输入流读取客户端发送过来的一行字符串的操作,可能会因为客户端的异常断开而抛出异常
             * java.net.SocketException: Connection reset
             */
            String line;
            while (true) {
                line = scanner.nextLine(); //获取控制台输入的内容
                // equalsIgnoreCase忽略大小写
                if ("exit".equalsIgnoreCase(line)) {
                    break; //停止循环
                }
                pw.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                /* Socket提供了close方法,该方法内部会通过他获取到的输入流和输出流
                并且全部关闭,同时还会跟远端计算机做最后四次挥手动作(TCP协议断开的操作)
                */
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
        Client client = new Client();
        client.start();
    }
    /**
     * 该线程任务负责处理服务端发过来的消息
     */
    private class ServerHandler implements Runnable{
        @Override
        public void run() {
            try {
                // 通过socket获取输入流读取服务端发送过来的消息
                InputStream in = socket.getInputStream();
                InputStreamReader isr = new InputStreamReader(in, StandardCharsets.UTF_8);
                BufferedReader br = new BufferedReader(isr);
                String line;
                // 循环读取服务端发送过来的每一行字符串
                while ((line = br.readLine())!=null) {
                    System.out.println(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
/**
 * 聊天室的服务端
 */
public class Server {
    /**
     * java.net.ServerSocket
     * 运行在服务端上,主要有两个职责:
     * 1.向系统申请服务端口,客户端就是通过该端口与服务端建立连接的
     * 2.监听该端口,一旦一个客户端建立连接,就会立即返回一个Socket实例,使用它就可以与该客户端交互了
     */
    private ServerSocket serverSocket;
    private PrintWriter[] allOut = {};
    public Server() {
        try {
            /**
             * 实例化ServerSocket的同时指定服务端口,客户端就可以通过该端口与服务端建立连接了。
             * 注意,该端口不能与服务器计算机上其他程序申请的端口一致,否则会抛出异常
             * 解决办法:换一个端口,或者将占用8088端口的进程杀死
             * 端口的选择:范围是0~65535之间的数字。但是实际开发中前6000不建议选取,
             * 因为密集绑定了系统应用和流行的应用程序,建议8000以后的端口
             */
            System.out.println("正在启动服务端...");
            serverSocket = new ServerSocket(8088);
            System.out.println("服务端启动完毕!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void start() {
        try {
            while (true) {
                /**
                 * ServerSocket的方法:
                 * Socket accept()
                 * 该方法是一个阻塞方法,调用后开始等待客户端的连接,一旦一个客户端连接了,
                 * accept方法会立即返回一个Socket实例,通过这个Socket可以与连接的客户端进行交互
                 * 多次调用accept可以接收多个客户端的连接
                 */
                System.out.println("等待客户端连接");
                Socket socket = serverSocket.accept();// 接收客户端连接
                System.out.println("一个客户端连接了");
                // 启动一个线程来处理该客户端交互
                ClientHandler clientHandler = new ClientHandler(socket);
                Thread thread = new Thread(clientHandler);
                thread.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Server server = new Server();
        server.start();
    }

    private class ClientHandler implements Runnable {
        private Socket socket;
        private String host; //记录远端计算机的ip

        /*一个类给另一个类传参,可以用构造方法*/
        public ClientHandler(Socket socket) {
            this.socket = socket;
            host = socket.getInetAddress().getHostAddress();
        }

        @Override
        public void run() {
            PrintWriter pw = null;
            try {
                /**
                 * 通过Socket方法
                 * getInputStream() 获取一个字节输入流,来读取远端计算机发送过来的字节
                 */
                InputStream in = socket.getInputStream();
                InputStreamReader isr = new InputStreamReader(in, StandardCharsets.UTF_8);
                BufferedReader br = new BufferedReader(isr);

                // 通过socket获取输出流用于给对方发送消息
                OutputStream out = socket.getOutputStream(); //通过该流写出的字节就发给了远端计算机
                OutputStreamWriter osw = new OutputStreamWriter(out, StandardCharsets.UTF_8);
                BufferedWriter bw = new BufferedWriter(osw);
                pw = new PrintWriter(bw,true);

                //1.将该输出流存入共享数组allOut中
                allOut = Arrays.copyOf(allOut, allOut.length + 1);
                //2.将pw放到数组最后一个格子里
                allOut[allOut.length - 1] = pw;

                String message;
                while ((message = br.readLine()) != null) {
                    sendMessage(host+"上线了,当前人数:"+allOut.length);
                    sendMessage(host+"说:"+message);
                }
            } catch (IOException e) {
                // e.printStackTrace();
            } finally {
                // 处理客户端断开连接后操作
                // 把pw从数组allOut中删除
                for (int i = 0; i < allOut.length; i++) {
                    if (allOut[i] == pw) {
                        allOut[i] = allOut[allOut.length - 1];
                        allOut = Arrays.copyOf(allOut, allOut.length - 1);
                        break;
                    }
                }
                sendMessage(host+"下线了,当前人数:"+allOut.length);
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        /**
         * 将消息发给所有客户端
         * @param message
         */
        private void sendMessage(String message) {
            System.out.println(message);//在服务端输出所客户端交互的记录
            // 遍历allOut数组,将消息发给所有客户端
            for (int i = 0; i < allOut.length; i++) {
                allOut[i].println(message);
            }
        }
    }
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值