自用JAVA笔记

Java中有8种基本数据类型

byte占1个字节8位,取值范围为-27~27-1

int占4个字节32位,取值范围为-231~231-1

short占2个字节16位,取值范围为-215~215-1

long占8个字节64位,取值范围为-263~263-1

float占4个字节32位,取值范围为3.402823e+38 ~ 1.401298e-45

double占8个字节64位,取值范围为1.797693e+308~ 4.9000000e-324

char占2个字节16位,取值范围为0~65535

boolean即true或false

JVM、JRE、JDK区别

JVM:(Java Virtual Machine)

Java虚拟机,只认识xxx.class这种类型的文件, 它能够将 class 文件中的字节码指令进行识别并调用操作系统向上的 API 完成动作。所以说,Jvm 是 Java 能够跨平台的核心。

Java虚拟机栈是描述java方法运行过程的内存模型,每个方法在执行的同时都会创建一个栈帧的区域,用于存储局部变量表,操作数栈、动态链接表、方法出口等信息。每一个方法的调用直至完成的过程,就对应着一个栈帧在虚拟机中入栈到出栈的过程。StackOverflowError表示请求栈深度大于虚拟机所允许的最大深度,可能内存还有很多。无法申请足够内存OutOfMemoryError。

JRE:(Java Runtime Environment)

Java 运行时环境。它主要包含两个部分,Jvm 的标准实现和 Java 的一些基本类库。它相对于 jvm 来说,多出来的是一部分的 Java 类库。

JDK :(Java Development Kit)

Java 开发工具包,Jdk 是整个 Java 开发的核心,它集成了 Jre 和一些好用的小工具。例如:javac.exe,java.exe,jar.exe 等。

三者的关系是:一层层的嵌套关系。JDK>JRE>JVM

Java 为什么能跨平台,实现一次编写,多处运行?

Java 能够跨平台运行的核心在于 JVM 。不是 Java 能够跨平台,而是它的 Jvm 能够跨平台。不同的操作系统向上的 API 肯定是不同的,要针对不同系统的 API 写出不同的代码来完成指定动作。

而 Java 引入了字节码的概念,Jvm 只能认识字节码,并将它们解释到系统的 API 调用。针对不同的系统有不同的 Jvm 实现,有 Linux 版本的 Jvm 实现,也有 Windows 版本的 Jvm 实现,但是同一段代码在编译后的字节码是一样的。在 Java API 层面,我们调用系统声音设备的代码是唯一的,和系统无关,编译生成的字节码也是唯一的。但是同一段字节码,在不同的 Jvm 实现上会映射到不同系统的 API 调用,从而实现代码的不加修改即可跨平台运行。

线程处理

1.标注位中断线程

  1. 设置标注位flag
  2. 设置公开线程的方法停止线程,转换标注位

2.线程休眠sleep

  1. sleep指定当前线程阻塞的毫秒数;
  2. sleep存在异常抛出
  3. sleep时间到达后线程进入就绪状态
  4. sleep可以模拟网络延时,倒计时等;
  5. 每一个对象都有一个锁,sleep不会释放锁

时间获取及输出格式

1.时间获取

Date startTime = new Date(System.currentTimeMillis());

2.输出格式

System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));

线程礼让yield

  1. 礼让线程,让当前正在执行的线程暂停,但不阻塞
  2. 将线程从运行状态转为就绪状态
  3. 让CPU重新调度,礼让不一定成功

线程强制执行join

join合并线程,等待此线程执行完成后,再执行其他线程,其他线程阻塞

TestJoin testJoin = new TestJoin();
Thread thread = new Thread(testJoin);
thread.start();
thread.join();

线程状态

  1. new
  2. runnable
  3. waiting
  4. Terminated,死亡后的线程不能再启动
Thread.State state=thread.getState();

线程优先级

t2.setPriority(1);
t2.start();
  1. 先设置优先级,在开启线程
  2. 优先级范围 (0,10]
  3. 优先级高仅代表执行的概率高,最终还是要取决于CPU的调度

守护线程daemon

Thread thread = new Thread(god);
thread.setDaemon(true);
thread.start();
  1. 线程分为用户线程和守护线程
  2. 用户线程结束则中断守护线程

线程同步

并发:同一个对象被多个进程同时操作

synchronized(obj){} 锁对象obj

可以用以下代码创建安全的list:

CopyOnWriteArrayList<String>list = new CopyOnWriteArrayList<String>();

callable:

  1. 实现Callable接口,需要返回值类型

  2. 重写call()方法,需要抛出异常

  3. 创建目标对象

  4. 创建执行服务器: ExecutorService ser = Executors.newFixedThreadPool(3);

  5. 提交执行:Future r1 = ser.submit(testThread01);

  6. 获取结果: boolean r1 = result1.get();

  7. 关闭服务: ser.shutdownNow();

  8. 另一种运行方式:

    FutureTask<Integer> futureTask = new FutureTask<Integer>(MyThread());
    

Lock锁

  1. Lock是显示锁,手动开启手动关闭,synchronized是隐式锁,出了作用域自动释放。
  2. Lock只有代码锁,synchronized有代码锁和方法锁。
  3. 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好,并且有更好的扩展性。
ReentrantLock lock = new ReentrantLock();
 try {
        lock.lock();
 }
finally {
         lock.unlock();
}

线程池

  1. JDK5.0提供了线程池相关的API:ExecutorSerivce 和 Executors
  2. ExecutorSerivce真正的线程池接口。常见子类ThreadPoolExecutor
  3. Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池
ExecutorService service = Executors.newFixedThreadPool(10);
service.execute(new MyThread());
service.shutdownNow();

GUI编程

组件:

  1. 窗口

  2. 弹窗

  3. 面板

  4. 文本框

  5. 列表框

  6. 按钮

  7. 图片

  8. 监听事件

  9. 鼠标

  10. 键盘事件

1. 简介

GUI的核心技术: Swing AWT

  1. 因为界面不美观
  2. 需要jre环境

为啥要学?

  1. 可以写出自己心中想要的一些工具
  2. 工作时候,也可能需要维护swing界面
  3. 了解MVC架构,了解监听!

2. AWT

2.1 AWT介绍

  1. 包含了很多类和接口,GUI : 图形用户界面编程

  2. 元素:窗口,按钮,文本框

  3. java.awt

2.2 组件和容器

 Frame frame = new Frame("我的窗口");
//设置可见性
frame.setVisible(true);
//设置窗口大小
frame.setSize(400,400);
//设置背景颜色
frame.setBackground(new Color(81, 82, 82));
//设置初始位置
frame.setLocation(200, 200);
//固定大小
frame.setResizable(false);

2.3 面板

package com.zzc.lesson01;

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

public class TestPanel {
    public static void main(String[] args) {
        Frame frame = new Frame();
        //布局
        Panel panel = new Panel();
        //设置布局
        frame.setLayout(null);
        //坐标
        frame.setBounds(300,300,500,500);
        frame.setBackground(Color.white);
        //panel设置坐标,相对于Frame
        panel.setBounds(50,50,400,400);
        panel.setBackground(Color.red);
        //frame.add(panel)
        frame.add(panel);
        
        frame.setVisible(true);
        //监听事件,监听窗口关闭事件
        //适配器模式
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
    }
}

2.3 布局管理器

  1. 流式布局

            Frame frame = new Frame();
    
            //组件-按钮
            Button button1 = new Button("button1");
            Button button2 = new Button("button2");
            Button button3 = new Button("button3");
            //设置为流式布局
            //frame.setLayout(new FlowLayout());
            frame.setLayout(new FlowLayout(FlowLayout.RIGHT));
    
            frame.setSize(200,200);
            //把按钮添加上去
            frame.add(button1);
            frame.add(button2);
            frame.add(button3);
    
    
  2. 东南西北中

    		Frame frame = new Frame("BorderLayout");
    
            Button east = new Button("East");
            Button north = new Button("North");
            Button west = new Button("West");
            Button south = new Button("South");
            Button center = new Button("Center");
    
            frame.add(east, BorderLayout.EAST);
            frame.add(north, BorderLayout.NORTH);
            frame.add(west, BorderLayout.WEST);
            frame.add(south, BorderLayout.SOUTH);
            frame.add(center, BorderLayout.CENTER);
    
  3. 表格布局

        Frame frame = new Frame();
        //组件-按钮
        Button button1 = new Button("button1");
        Button button2 = new Button("button2");
        Button button3 = new Button("button3");
        Button button4 = new Button("button4");

        frame.setLayout(new GridLayout(2,2));
        frame.add(button1);
        frame.add(button2);
        frame.add(button3);
        frame.add(button4);

        frame.pack();//java函数,自动最优布局

总结

  1. frame是一个顶级窗口

  2. Panel无法单独显示,必须加到某个容器中

  3. 布局管理器

    1.流式

    2.东南西北中

    3.表格

  4. 大小,定位,背景颜色,可见性,监听

2.4 事件监听

事件监听:当某个事情发生了,干什么

 MyActionListener myActionListener = new MyActionListener();
 button.addActionListener(myActionListener);
class MyActionListener implements ActionListener{

    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("aaa");
    }
}
b2.setActionCommand("button2-stop");

class MyMontior implements ActionListener{

    @Override
    public void actionPerformed(ActionEvent e) {
		//获取按钮名称
        System.out.println("按钮被点击了:msg"+e.getActionCommand());


    }
}
class MyFrame2 extends Frame{
    public MyFrame2(){
        TextField textField = new TextField();
        add(textField);
        //监听这个文本框输入的文子
        Myaction2 myaction2 = new Myaction2();
        //按下enter 就会触发这个输入框的事件
        textField.addActionListener(myaction2);
        //加密
        textField.setEchoChar('*');
        setVisible(true);
        //pack();
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

    }

}

class Myaction2 implements ActionListener{
    @Override
    public void actionPerformed(ActionEvent e) {
        //获取输入内容
        TextField textField = (TextField) e.getSource();
        System.out.println(textField.getText());
        textField.setText("");
    }
}

2.5 计算器

package com.zzc.lesson01;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class Calculator2 {
    public static void main(String[] args) {
        new Cac();
    }
}

class Cac2 extends Frame{
    //属性
    TextField textField1,textField2,textField3;
    Button button;
    Label label;
    //方法
    public Cac2(){
        this.textField1 = new TextField(10);
        this.textField2 = new TextField(10);
        this.textField3 = new TextField(20);
        this.textField3.setEditable(false);
        this.button = new Button("=");
        this.button.addActionListener(new MyCacListener());
        this.label = new Label("+");
        setLayout(new FlowLayout());
        add(textField1);
        add(label);
        add(textField2);
        add(button);
        add(textField3);
        pack();
        setVisible(true);
        setLocation(400,400);
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
    }
    //监听器类
    private class MyCacListener implements ActionListener {


        @Override
        public void actionPerformed(ActionEvent e) {
            //1.获得加数和被加数
            int n1 = 0;
            int n2 = 0;

            if (!textField1.getText().equals("")){
                n1 = Integer.parseInt(textField1.getText());
            }
            if (!textField2.getText().equals("")){
                n2 = Integer.parseInt(textField1.getText());
            }
            //2.将这个值加法运算后,放到第三个框
            textField3.setText(""+(n1+n2));
            //3.清除前两个框
            textField1.setText("");
            textField2.setText("");
        }
    }

}


2.6 画板

public void paint(Graphics g){
       //画笔需要有颜色
        g.setColor(Color.red);
    //空心圆
        g.drawOval(100,100,100,100);
        g.setColor(Color.blue);
        g.fillOval(100,200,100,100);
    //实心圆
        g.setColor(Color.GREEN);
    //实心正方形
        g.fillRect(200,100,100,100);
        //用完画笔,将他还原到最初的颜色
        g.setColor(Color.BLACK);
    }

2.7 鼠标画板

package com.zzc.lesson01;

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;

public class TestMouseListener {
    public static void main(String[] args) {
        new MyFrame3("画板");
    }
}


class MyFrame3 extends Frame{
    ArrayList points;
    //需要画板,需要监听鼠标当前位置,需要集合来储存这些点
    public MyFrame3(String title){
        super(title);
        setBounds(200,200,800,800);
        //鼠标监听器,正对这个窗口
        this.addMouseListener(new MyMouseListener());
        points = new ArrayList<>();

        setVisible(true);
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

    }

    @Override
    public void paint(Graphics g) {
        //画画,监听鼠标的事件
        Iterator iterator = points.iterator();
        while (iterator.hasNext()){
            Point point = (Point) iterator.next();
            g.setColor(Color.BLACK);
            g.fillOval(point.x,point.y,10,10);
        }
    }

    //添加一个点到界面上
//    public void addPaint(Point point){
//        points.add(point);
//    }
    //适配器模式
    private class MyMouseListener extends MouseAdapter {
        //鼠标 按下,弹起,按住不放

        @Override
        public void mousePressed(MouseEvent e) {
            MyFrame3 frame = (MyFrame3) e.getSource();
            //点击时,产生一个点
            //这个点就是鼠标的点
            points.add(new Point(e.getX(),e.getY()));
           //每次点击鼠标重画一次
            frame.repaint();
        }
    }
}

2.8 按键清空画板

private class CleanPaint implements ActionListener {
        MyFrame3 myFrame3;
        public CleanPaint(MyFrame3 frame3){
            this.myFrame3 = frame3;
        }
        @Override
        public void actionPerformed(ActionEvent e) {
            points.clear();
            this.myFrame3.repaint();
        }
    }

2.9 窗口监听

2.10 键盘监听

 this.addKeyListener(new KeyAdapter() {
                           @Override
                           public void keyPressed(KeyEvent e) {
                               int keyCode = e.getKeyCode();
                               //获得键盘按下的键是哪一个
                               if (keyCode==KeyEvent.VK_UP){
                                   System.out.println("按下上键");
                               }

                           }
                       }
        );
    }

3. Swing

3.1 窗口、面板

package com.zzc.lesson01;

import javax.swing.*;
import java.awt.*;

public class TestJFrame {
    //init() 初始化
    public void init(){
        JFrame frame = new JFrame("JFrame");
        frame.setVisible(true);
        frame.setBounds(400,200,400,400);
        //frame.setBackground(Color.white);
        //设置文字JLabel
        JLabel label = new JLabel("Welcome");
        frame.add(label);
        //让文本标签居中(0:center 1:Top 2:Left 3:Bottom 4:Right)
        label.setHorizontalAlignment(SwingConstants.CENTER);
        //关闭
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        //容器实例化
        frame.getContentPane().setBackground(Color.red);
    }

    public static void main(String[] args) {
        new TestJFrame().init();
    }
}

3.2 弹窗

class MyDialog extends JDialog{
    public MyDialog(){
        this.setVisible(true);
        this.setBounds(100,100,500,500);
        //this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        JLabel label = new JLabel("Dialog2");
        add(label);
        label.setHorizontalAlignment(0);

    }
}

3.3 标签

#### label

new JLabel("xxx");

Icon

package com.zzc.lesson01;

import javax.swing.*;
import java.awt.*;

//图标,需要实现类,Frame继承
public class TestIcon extends JFrame implements Icon {

    private int width;
    private int height;

    public TestIcon(){}
    public TestIcon(int width, int height){
        this.width = width;
        this.height = height;
    }
    public void init(){
        TestIcon testIcon = new TestIcon(15,15);
        JLabel label = new JLabel("Icon", testIcon,0);
        setBounds(100,100,300,300);
        Container container = getContentPane();
        container.add(label);

        this.setVisible(true);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }
    public static void main(String[] args) {
        new TestIcon().init();
    }

    @Override
    public void paintIcon(Component c, Graphics g, int x, int y) {
        g.fillOval(x,y,width,height);
        System.out.println(x+"    "+y);
    }

    @Override
    public int getIconWidth() {
        return this.width;
    }

    @Override
    public int getIconHeight() {
        return this.height;
    }
}

ImageIcon

package com.zzc.lesson01;

import javax.swing.*;
import java.awt.*;
import java.net.URL;

public class TestImageIcon extends JFrame {
    public TestImageIcon(){
        super("TestImageIcon");
        JLabel label = new JLabel();
        //获取图片地址
        URL url = TestImageIcon.class.getResource("zzc.jpg");
        System.out.println(url);
        ImageIcon imageIcon = new ImageIcon(url);
        label.setIcon(imageIcon);
        label.setHorizontalAlignment(SwingConstants.CENTER);
        Container contentPane = getContentPane();
        contentPane.add(label);

        setBounds(100,100,300,300);
        setVisible(true);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

    }
    public static void main(String[] args) {
        new TestImageIcon();
    }
}

3.4 面板

package com.zzc.lesson01;

import javax.swing.*;
import java.awt.*;

public class TestJPanel extends JFrame {
    public TestJPanel(){
        Container container = getContentPane();
        container.setLayout(new GridLayout(2,1,10,10));//后面为间距参数
        JPanel panel = new JPanel(new GridLayout(1,3));

        panel.add(new Button("1"));
        panel.add(new Button("1"));
        panel.add(new Button("1"));

        container.add(panel);

        setVisible(true);
        setSize(500,500);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {
        new TestJPanel();
    }

}

JScrollPanel

package com.zzc.lesson01;

import javax.swing.*;
import java.awt.*;

public class TestJScroll extends JFrame {
    public TestJScroll(){
        Container container = getContentPane();
        //文本域
        JTextArea jTextArea = new JTextArea(23,40);
        //jTextArea.setText("zzc");
        //container.add(jTextArea);
        //Scroll面板
        JScrollPane scrollPane = new JScrollPane(jTextArea);
        container.add(scrollPane);

        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setVisible(true);
        setBounds(100,100,400,400);
    }

    public static void main(String[] args) {
        new TestJScroll();
    }
}

3.5 按钮

图标按钮

package com.zzc.lesson01;

import javax.swing.*;
import java.awt.*;
import java.net.URL;

public class TestJButton extends JFrame {

    public TestJButton(){
        Container container = getContentPane();
        JButton jButton = new JButton();
        //将一个图片变为图标
        URL url = TestJButton.class.getResource("zzc.jpg");
        Icon icon = new ImageIcon(url);
        //把这个图标放到按钮上
        jButton.setIcon(icon);
        jButton.setToolTipText("Picture Button");
        container.add(jButton,BorderLayout.SOUTH);


        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setBounds(100,100,300,300);
        container.setBackground(Color.white);
        setVisible(true);

    }


    public static void main(String[] args) {
        new TestJButton();
    }
}

单选框

package com.zzc.lesson01;

import javax.swing.*;
import java.awt.*;
import java.net.URL;

public class TestJButton2 extends JFrame {

    public TestJButton2(){
        Container container = getContentPane();
        //单选框
        JRadioButton radioButton1 = new JRadioButton("1");
        JRadioButton radioButton2 = new JRadioButton("2");
        JRadioButton radioButton3 = new JRadioButton("3");
        JRadioButton radioButton4 = new JRadioButton("4");
        //由于单选框只能选一个,分组
        ButtonGroup buttonGroup = new ButtonGroup();
        //一组只能选一个
        buttonGroup.add(radioButton1);
        buttonGroup.add(radioButton2);
        buttonGroup.add(radioButton3);
        buttonGroup.add(radioButton4);

        container.setLayout(new GridLayout(4,1,10,10));
        container.add(radioButton1);
        container.add(radioButton2);
        container.add(radioButton3);
        container.add(radioButton4);


        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setBounds(100,100,300,300);
        //container.setBackground(Color.white);
        setVisible(true);

    }


    public static void main(String[] args) {
        new TestJButton2();
    }
}

多选框

package com.zzc.lesson01;

import javax.swing.*;
import java.awt.*;
import java.net.URL;

public class TestJButton3 extends JFrame {

    public TestJButton3(){
        Container container = getContentPane();

        //多选框
        JCheckBox checkBox1 = new JCheckBox("1");
        JCheckBox checkBox2 = new JCheckBox("2");
        JCheckBox checkBox3 = new JCheckBox("3");
        JCheckBox checkBox4 = new JCheckBox("4");

        container.setLayout(new FlowLayout());
        container.add(checkBox1);
        container.add(checkBox2);
        container.add(checkBox3);
        container.add(checkBox4);


        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setBounds(100,100,300,300);
        //container.setBackground(Color.white);
        setVisible(true);

    }


    public static void main(String[] args) {
        new TestJButton3();
    }
}


3.6 列表

下拉框

package com.zzc.lesson01;

import javax.swing.*;
import java.awt.*;

public class TestList extends JFrame {
    public TestList(){
        Container container = getContentPane();
        //创建下拉框
        JComboBox status = new JComboBox();
        
        status.addItem(null);
        status.addItem("1");
        status.addItem("2");
        status.addItem("3");
        
        container.add(status);
        
        
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        this.setVisible(true);
        this.setBounds(100,100,400,400);
    }
    public static void main(String[] args) {
        new TestList();
    }
}

静态列表

package com.zzc.lesson01;

import javax.swing.*;
import java.awt.*;
import java.util.Vector;

public class TestList2 extends JFrame {
    public TestList2(){
        Container container = getContentPane();

        //生成列表的内容
        //String[] contents = {"1","2","3","4"};
        Vector contents = new Vector();
        JList jList = new JList(contents);

        container.add(jList);
        contents.add("1");


        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        this.setVisible(true);
        this.setBounds(100,100,400,400);
    }
    public static void main(String[] args) {
        new TestList2();
    }
}

应用场景

  1. 选择地区,或者一些单个选项
  2. 列表展示信息,动态扩容

3.7 文本框

文本框

new JText();

密码框

new JPassWordField();

文本域

new JTestArea();

贪吃蛇

键盘监听

定时器

JAVA 刷题笔记

  1. 对String操作可以用StringBuider,能实现添加append,倒叙reverse。
  2. s.substring(i,i+m)可截取s片段
  3. 打印二维数组的方法Array.toString(arr[i]);
  4. 扩容数组可以用arr = Array.Copyof(arr, arr.length + i);
  5. 将数放入List<List>中,res.add(new ArrayList(Arrays.asList(nums[k], nums[i], nums[j])));
  6. 在Hashmap中,可用map.getofdefalut(i,j)得到j值或者0,取决于是否存在(i,j);
  7. LinkedList 可以创建链表,更灵活处理数据。

网络编程

1. 概念

计算机网络: 计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统网络管理软件网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。

网络编程目的: 无线电台,传播交流信息,数据交换,通信

想要达到这个效果需要什么:

1.如何准确定位网络上的一台主机:192.168.16.124: 端口,定位到这个计算机上的某个资源

2.找到了这个主机,如何传输数据?

javaweb:B/S 网页编程

网络编程:TCP/IP

1.2 网络通信的要素

如何实现网络通信?

  • ip
  • 端口号
  • ip+端口

规则:网络通信协议

[TCP/IP][ https://baike.baidu.com/item/TCP%2FIP%E5%8D%8F%E8%AE%AE/212915?fromtitle=tcp%2Fip&fromid=214077&fr=aladdin]

小结:

  1. 网络编程中的主要问题

    • 如何准确定位网络上的一台或多台主机
    • 找到主机之后如何通信
  2. 网络编程中的要素

    • IP和端口
    • 网络通信协议
  3. 万物皆对象

1.3 IP

IP地址: InetAddress

  • 唯一定位一台网络计算机

  • 127.0.0.1:本机localhost

  • IP分类:

    • ipv4/ipv6

      • ipv4:127.0.0.1, 4个字节组成。0~255,42亿;30亿在北美,亚洲4亿

      • IPV6:ipconfig可查看本机IP地址,128位

        2001:0bb2:aaaa:0015:0000:0000:1aaa:1312
        
    • 公网(互联网)-私网(局域网)

      • 192.168.xx.xx 专门给组织内使用
      • [ABCD类地址][https://blog.csdn.net/weixin_43378197/article/details/102841275]
  • 域名:记忆IP问题!

1.4 端口

端口表示计算机上的一个程序进程;

  • 不同的进程有不同的端口号!用来区别软件!

  • 被规定0~65535

  • TCP,UDP:65535 * 2 单个协议下端口不能重复

  • 端口分类:

    • 公有端口:0~1023

      • HTTP: 80
      • HTTPS:443
      • FTP:21
      • Telent:23
    • 程序注册端口:1024~49151,分给用户或程序

      • Tomcat:8080
      • MySQL:3306
      • Oracle:1521
    • 动态、私有:49152~65535

      netstat -ano //cmd中查看所以端口
      netstat -ano|findstr "5900" //查看指定的端口
      tasklist|findstr "8696" //查看指定端口进程
      
      InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 8080);
      System.out.println(inetSocketAddress);
      System.out.println(inetSocketAddress.getAddress());
      System.out.println(inetSocketAddress.getHostName()); //地址
      System.out.println(inetSocketAddress.getPort());//端口
      

1.5 通信协议

网络通信协议 :速率,传输码率,代码结构,传输控制。。。

TCP/IP:实际上是一种协议

TCP:用户传输协议(类似打电话)1. 连接,稳点。2.三次握手,四次挥手。3.客户端、服务端。4.传输完成,释放连接,效率低。

UDP:用户数据协议(类似发短信)1.不连接,不稳定。2.没有明确客户端服务端界限。3.都发给你。

出名协议:

TCP

IP:网络互连协议

1.6 TCP

客户端

  1. 连接服务器Socket

  2. 发送信息

    //客户端
    public class TcpClientdemo01 {
        public static void main(String[] args) {
            Socket socket = null;
            OutputStream os = null;
            try {
                //1.要知道服务器地址,端口号
                InetAddress address = InetAddress.getByName("127.0.0.1");
                int port = 9999;
                //2.创建一个socket连接
                socket = new Socket(address,port);
                os = socket.getOutputStream();
                os.write("你好".getBytes());
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (os != null){
                    try {
                        os.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (socket != null){
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
    

服务器

  1. 建立服务端口ServerSocket
  2. 等待用户连接accept
  3. 接收用户消息
//服务器
public class TcpServerDemo01 {
    public static void main(String[] args) throws IOException {
        //1.地址
        ServerSocket serverSocket = new ServerSocket(9999);
        //2. 等待客户端连接过来
        Socket accept = serverSocket.accept();
        //3.读取客户端的消息
        InputStream inputStream = accept.getInputStream();
        //管道流
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = inputStream.read(buffer))!=-1){
            baos.write(buffer,0,len);
        }
        System.out.println(baos.toString());

        if (baos != null){
            baos.close();
        }
        if (inputStream != null) {
            inputStream.close();
        }
        if (serverSocket != null){
        serverSocket.close();
        }
    }
}

文件上传

//客户端
package com.zzc;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.logging.SocketHandler;

public class TcpClient02 {
    public static void main(String[] args) throws IOException {
        //1.创建一个Socket
        Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9000);
        //2.创建一个输出流
        OutputStream os = socket.getOutputStream();
        //3.文件流
        FileInputStream fis = new FileInputStream(new File("photo.jpg"));
        //4.写出文件
        byte[] buffer = new byte[1024];
        int len;
        while ((len = fis.read(buffer))!=-1){
            os.write(buffer,0 ,len);
        }
        //通知服务器,传输完毕
        socket.shutdownOutput();

        //确定服务器接收完毕,才能断开连接
        InputStream inputStream = socket.getInputStream();
        //String
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer2 = new byte[2014];
        int len2;
        while ((len2 = inputStream.read(buffer2))!=-1){
            baos.write(buffer,0 ,len2);
        }
        System.out.println(baos.toString());

        //5.关闭
        baos.close();
        inputStream.close();
        fis.close();
        os.close();
        socket.close();
    }
}
//服务器
package com.zzc;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class TcpServer02 {
    public static void main(String[] args) throws IOException {
        //1.创建服务
        ServerSocket serverSocket = new ServerSocket(9000);
        //2.监听客户端连接
        Socket socket = serverSocket.accept();//阻塞式监听,一直等待客户端连接
        //3.获取输入流
        InputStream is = socket.getInputStream();

        //4.文件输出
        FileOutputStream fos = new FileOutputStream(new File("receive.jpg"));
        byte[] buffer = new byte[1024];
        int len;
        while ((len = is.read(buffer))!=-1){
            fos.write(buffer);
        }

        //通知客户端完成接收
        OutputStream os = socket.getOutputStream();
        os.write("接收完毕".getBytes());

        fos.close();
        is.close();
        socket.close();
        serverSocket.close();
    }
}

1.7 Tomcat

服务端

  • 自定义 S
  • Tomcat服务器S:JAVA后台开发

客户端

  • 自定义 C
  • 浏览器 B

1.8 UDP

发送消息

package com.zzc;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

public class UDPClient01 {
    public static void main(String[] args) throws Exception {
        //1.建立一个Socket
        DatagramSocket socket = new DatagramSocket(8080);
        //2.建立包
        String msg = "hello";
        //发给谁
        InetAddress local = InetAddress.getByName("localhost");
        int port = 9090;
        //数据,数据的长度起始,要发给谁
        DatagramPacket packet = new DatagramPacket(msg.getBytes(),0,msg.getBytes().length,local,port);
        //3.发送包
        socket.send(packet);

        //关闭流
        socket.close();
    }
}

接收端

package com.zzc;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
//还是要等待客户端的连接
public class UDPServer01 {
    public static void main(String[] args) throws Exception {
        //开发端口
        DatagramSocket socket = new DatagramSocket(9090);
        // 接收数据包
        byte[] buffer = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
        socket.receive(packet);//阻塞接收
        System.out.println(new String(packet.getData()));
        System.out.println(packet.getAddress());
        System.out.println(packet.getAddress().getHostAddress());
        //关闭
        socket.close();
    }
}

循环发送

package com.zzc.chat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;

public class UDPSender01 {
    public static void main(String[] args) throws IOException {
        DatagramSocket socket = new DatagramSocket(8888);
        while (true) {
            //准备数据:控制台读取System.in
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            String data = reader.readLine();

            byte[] datas = data.getBytes();
            DatagramPacket packet = new DatagramPacket(datas, 0, datas.length, new InetSocketAddress("localhost", 6060));

            socket.send(packet);
            if (data.equals("bye")){
                break;
            }
        }
        socket.close();
    }
}

循环接收

package com.zzc.chat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;

public class UDPRerver01 {
    public static void main(String[] args) throws IOException {
        DatagramSocket socket = new DatagramSocket(6060);
        while (true) {
            //准备接收数据
            byte[] container = new byte[1024];
            DatagramPacket packet = new DatagramPacket(container, 0, container.length);
            socket.receive(packet);//阻塞式接收包
            //断开连接
            byte[] data = packet.getData();
            String s = new String(data, 0, data.length);
            System.out.println(s);
            if (s.equals("bye")) {
                System.out.println("break");
                break;

            }

        }
        socket.close();
    }
}

1.9 URL

统一资源定位符:定义资源,定位到互联网上的某一个资源

DNS域名解析 www.xxx.com - > 123.000.000

协议://ip地址:端口/项目名/资源

下载

package com.zzc.chat;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class URLDownLoad {
    public static void main(String[] args) throws IOException {
        //1. 下载地址
        URL url = new URL("https://static.youku.com/v201803261000.0/v/swf/upsplayer/player_yknpsv.swf");
        //2.连接到这个资源 HTTP
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

        InputStream inputStream = urlConnection.getInputStream();

        FileOutputStream fileOutputStream = new FileOutputStream("player_yknpsv.swf");

        byte[] buffer = new byte[1024];
        int len;
        while ((len = inputStream.read(buffer))!=-1){
            fileOutputStream.write(buffer,0,len);//写出数据
        }

        fileOutputStream.close();
        inputStream.close();
        urlConnection.disconnect();
    }
}

注解和反射

1. 注解

不是程序本身,可以对程序作出解释

可以被其他程序读取。

@+注释名

内置注解:

@override 重写注释

@Deprecated 不推荐使用

@SuppressWaring(“all”)

2. 反射 Reflection

可以获得类的属性、方法、构造器、修饰符等等。

获取Class的方式

public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Student();
        System.out.println("This is "+ person.name);
        //方式一:通过对象获得
        Class c1 = person.getClass();
        //方式二:forname获得
        Class c2 = Class.forName("com.reflection.Student");
        System.out.println(c1.hashCode());
        System.out.println(c2.hashCode());
        //方式三:通过类名.class获得
        Class<Student> c3 = Student.class;
        //方式四:基本内置类型的包装类都有一个TYPE属性
        Class<Integer> c4 = Integer.TYPE;
        //获得父类
        Class c5 = c1.getSuperclass();
        System.out.println(c5);

    }

那些类有Class 对象:

class:外部类

interface:接口

[] :数组

enum:枚举

annotation:注解

primitive type:基本数据类型

void

2.1 何时发生类的初始化

package com.reflection;
//测试类什么时候会初始化
public class Test06 {
    static {
        System.out.println("Main加载");
    }
    public static void main(String[] args) throws ClassNotFoundException {
        //1.主动引用
        Son son = new Son();
        //2.反射产生主动引用
        Class.forName("com.reflection.Son");
        //3.不产生类的引用方法
        System.out.println(Son.b);
        //4.数组不会产生引用方法
        Son[] arry = new Son[10];
        //5.常量不会引发初始化
        System.out.println(Son.M);
    }
}
class Father{
    static int b =2;
    static {
        System.out.println("父类加载");
    }
}
class Son extends Father{
    static {
        System.out.println("子类加载");
        m = 300;
    }

    static int m = 100;
    static final int M = 1;
}

2.2 类加载器

源码->JAVA编译器-> 字节码 -> 类装载器 -> 字节码校验器 -> 解码器 -> 操作系统平台

作用:将class文件字节码内容加载到内存中,并将静态数据转换成方法区的运行时数据结构,然后在堆中生成java.lang.Class对象,作为方法区中类数据的访问入口。

package com.reflection;

public class Test07 {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取系统类的加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        //获取系统类的加载器的父类-->扩展类加载器
        ClassLoader parent = systemClassLoader.getParent();
        //获取扩展类加载器的父类-->根加载器(c/c++)
        ClassLoader parent1 = parent.getParent();
        System.out.println(systemClassLoader);
        System.out.println(parent);
        System.out.println(parent1);
        //测试当前类是那个加载器加载的
        ClassLoader classLoader = Class.forName("com.reflection.Test07").getClassLoader();
        System.out.println(classLoader);

        ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader1);
        //如何获得系统类加载其可以加载的路径
        System.out.println(System.getProperty("java.class.path"));
        //双亲委派机制,检测保证安全性,当自定义包名称与JDK中根加载器中包的重名,则自定义包无效

    }
}

2.3 通过反射动态创建对象

package com.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

//动态的创建对象,通过反射
public class Test09 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        Class c1 = Class.forName("com.reflection.User");

        //构造一个对象
        User o =(User) c1.newInstance();//调用无参构造
        System.out.println(o);

        //通过构造器创建对象
        Constructor constructor = c1.getConstructor(String.class, int.class, int.class);
        User zzc = (User) constructor.newInstance("zzc", 01, 18);
        System.out.println(zzc);
        //通过反射调用普通方法
        User user3 = (User) c1.newInstance();
        //通过反射获取一个方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        //invoke激活
        setName.invoke(user3,"zzc");
        System.out.println(user3.getName());
        //通过反射操作属性
        User user4 = (User) c1.newInstance();
        Field name = c1.getDeclaredField("name");
        //不能直接操作私有属性,需要关闭程序的安全检测,属性或方法的setAccessible(true);
        name.setAccessible(true);
        name.set(user4,"zzc1");
        System.out.println(user4.getName());

    }
}

2.4 通过反射获取注解

ORM:Object relationship Mapping --> 对象关系映射

//练习反射操作注解
public class Test11 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("com.reflection.Student2");

        //通过反射获取注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
        //获得注解value的值
        Tablezzc tablezzc = (Tablezzc) c1.getAnnotation(Tablezzc.class);
        System.out.println(tablezzc.value());
        //获取类指定的注解
        Field name = c1.getDeclaredField("id");
        Fieldzzc annotation = name.getAnnotation(Fieldzzc.class);
        System.out.println(annotation.columnName());
        System.out.println(annotation.type());
        System.out.println(annotation.length());
    }
}

JVM探究

  • 什么是JVM? java->class->jvm

  • java8虚拟机和之前的变化?

  • 什么OOM,什么是栈溢出StackOverFlowError?怎么分析?

  • JVM的常用调优参数有哪些?

  • 内存快照如何抓取,怎么分析Dump文件?

  • JVM中,类加载器的认识?rt-jar ext application

1. JVM的位置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pW8WOsfe-1582198522997)(C:\Users\zzc19941219\AppData\Roaming\Typora\typora-user-images\1582186103706.png)]

2. JVM的体系结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7xn9mN0w-1582198523000)(C:\Users\zzc19941219\AppData\Roaming\Typora\typora-user-images\1582186172562.png)]

3. 类加载器

作用:加载Class文件 new Student()

  1. 虚拟机自带的加载器
  2. 启动类加载器 rt.jar
  3. 扩展类加载器 \jre\lib\ext
  4. 应用程序加载器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vwu23non-1582198523001)(C:\Users\zzc19941219\AppData\Roaming\Typora\typora-user-images\1582186237222.png)]

3.1 委派机制

  1. 类加载器收到请求
  2. 将这个请求向上委托给父类加载去完成,一直向上直到启动类加载器
  3. 启动器加载器检查是否存在当前这个类,能加载就结束,使用当前加载器,否则,抛出异常,通知子加载器进行加载
  4. class Not Found

运行一个类时会向上找,查找更上层的加载其中是否存在同名的类,找到了则执行最上层的包,保证安全。

3.2 沙箱安全机制

  • 字节码校验器
  • 类装载器

3.3 Native

  • 凡是带了native关键字的,说明java的作用范围达不到了,回去调用c语言的库。

  • 会进入本地方法栈,调用本地方法本地接口 JNI

  • JNI作用:扩展JAVA使用,融合不同编程语言,c,c++

  • 内存中开辟一块标记区域:native method stack,登记native接口

  • 在最终执行时,加载本地方法库中的方法通过JNI

    调用其他接口:Socket…WedService http

4. PC寄存器

每个线程都有一个计数器,是线程私有的,是一个指针,指向方法区中的方法字节码(用来指向一条指令地址,也指向即将要执行的指令代码),在执行引擎读取下一条指令,内存空间小。

5. 方法区

方法区是内存共享的,所有字段和方法字节码,以及一些特殊方法,如构造函数,接口代码也在此定义,所有定义方法的信息都在这个区域保存,为共享区域。

**静态变量,常量,类信息(构造方法,接口定义)、运行时的常量池存在方法区中,但是实例变量存在堆内存中,和栈无法。**static,final,Class,常量池

6. 栈

栈是一种数据结构

程序 = 数据结构+ 算法

栈:先进后出,栈内存,主管程序的运行,生命周期与线程同步,线程结束,栈内存也释放。对于栈不存在垃圾回收问题。

栈:8大基本类型+对象引用+实例的方法

栈运行原理:栈帧

栈 + 堆 + 方法区 交互关系

队列: 先进先出(FIFO: First input first output)

栈具体怎么存,对象实力化的过程?

简单类对象的实例化过程

1、在方法区加载类;

2、在栈内存申请空间,声明变量P;

3、在堆内存中开辟空间,分配对象地址;

4、在对象空间中,对对象的属性进行默认初始化,类成员变量显示初始化;

5、构造方法进栈,进行初始化;

6、初始化完成后,将堆内存中的地址赋给引用变量,构造方法出栈;

子类对象的实例化过程

1、在方法区先加载父类,再加载子类;

2、在栈中申请空间,声明变量P;

3、在堆内存中开辟空间,分配对象地址;

4、在对象空间中,对对象的属性(包括父类的属性)进行默认初始化;

5、子类构造方法进栈;

6、显示初始化父类的属性;

7、父类构造方法进栈,执行完毕出栈;

8、显示初始化子类的属性;

9、初始化完毕后,将堆内存中的地址值赋给引用变量P,子类构造方法出栈;

7. 三种JVM

Sun公司 HotSpot

BEA JRokit

IBM

8. 堆

一个JVM只有一个堆,堆内存的大小是可以调节的。

类加载器读取了类文件后,类,方法,常量,变量~,保存所以引用类型真实对象。

堆内存分为三个区:

  • 新生区

  • 养老区

  • 永久区

    GC垃圾回收主要在新生区和养老区

    内存满,OOM,堆内存不够。

    在JDK8以后,永久区改名为(元空间)。

    99%的对象都是临时对象。

8.1 新生区

  • 类:诞生和成长,甚至死亡。
  • 伊甸园区:所有对象在这里new出来
  • 幸存者(0,1)

8.2 老年区

8.3 永久区

这个区域常驻内存,存放JDK自身携带的Class对象。Interface元数据,存储JAVA运行时的一些环境或类信息。这个区域不存在垃圾回收,关闭VM虚拟就会释放这个区域的内存。

一个启动类加载大量第三方jar包。Tomcat部署太多应用,大量动态生成反射类,不断的被加载,直到内存满就会OOM。

  • JDK 1.6 之前:永久代,常量池在方法区中
  • jdk1.7 :永久代,但在退化,去永久代。常量池在堆中
  • JDK1.8:无永久代,常量池在元空间

8.4 堆内存调优

package com.JVMStudy;

public class demo01 {
    public static void main(String[] args) {
        long max = Runtime.getRuntime().maxMemory();
        long total = Runtime.getRuntime().totalMemory();
        System.out.println("max = "+(max/1024/1024)+"MB");
        System.out.println("total = "+(total/1024/1024)+"MB");
        //默认情况下:分配的总内存是电脑内存的1/4,初始化内存1/64
    }
    //修改参数 VM option: -Xms1024m -Xmx1024m -XX:+PrintGCDetails
}

出现OOM的解决方法:

  1. 尝试扩大一下堆内存,看结果
  2. 分析内存,看一下那个地方出了问题(专业工具)

在一个项目中突然出现OOM故障,该如何排除

  • 能看到代码哪里出错:内存快照分析工具,MAT,Jprofiler
  • Dubug,一行一行分析

MAT,Jprofiler作用:

  • 分析Dump内存文件,快速定位内存泄漏:
  • 获得堆中数据
  • 获得大的对象

dump文件:-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError

-Xms:设置初始化内存分配大小 1/64

-Xmx:最大分配内存 1/4

-XX:+PrintGCDetails :打印GC垃圾回收信息

-XX:+HeapDumpOnOutOfMemoryError :oom dump文件

8.5 GC

作用在堆和方法区中

JVM在进行GC时,并不是对这个三个区域统一回收,大部分回收新生代

  • 新生代
  • 幸存区
  • 老年区

GC两种类:轻GC,重GC

题目:

  • JVM的内存模型和分区,区中有什么
  • 堆里有什么区?Eden,from,to,老年区,说说优点
  • GC的算法有哪些?标记清除法,标记压缩,复制算法,引用计数器,怎么用?
  • 轻GC和重GC分别在什么时候发生。
  1. [常用算法][https://blog.csdn.net/wuzhiwei549/article/details/80563134]

    • [复制算法][https://blog.csdn.net/yanghenan19870513/article/details/92803409]

      优点:没有内存碎片

      坏处:浪费了空间,多了一半空间永远是空to8

      复制算法最佳使用场景:对象存活较低的区域,新生区

    • 标记清除算法

      优点:不需要额外的空间

      缺点:两次扫描,严重浪费时间,会产生内存碎片

    • 标记压缩:标记清除算法之后,对对象进行排序,防止内存碎片。

    总结:

    • 内存效率:复制>标记清除>标记压缩
    • 内存整齐度:复制=标记压缩>标记清除
    • 内存利用率:标记压缩=标记清除算法>复制算法

    年轻代:存活率低,复制算法

    老年代:区域大,存活率低,标记清除+标记压缩

9. JMM (Java Memory Model)

  1. 什么是[JMM][https://www.cnblogs.com/yuxiang1/archive/2019/05/16/10875619.html]

  2. 干嘛用的?

    作用:缓存一致性协议,用于定义数据读写规则(遵守,找到)

    JMM定义了线程工作内存和主内存之间的抽象关系: 线程之间的共享变量储存在主内存(Main Memory)中,每个线程都有一个私有的本地内存(Local Memory)。

  3. 怎么学习。

    JMM对这八种指令的使用,制定了如下规则:

    • 不允许read和load、store和write操作之一单独出现。即使用了read必须load,使用了store必须write
    • 不允许线程丢弃他最近的assign操作,即工作变量的数据改变了之后,必须告知主存
    • 不允许一个线程将没有assign的数据从工作内存同步回主内存
    • 一个新的变量必须在主内存中诞生,不允许工作内存直接使用一个未被初始化的变量。就是怼变量实施use、store操作之前,必须经过assign和load操作
    • 一个变量同一时间只有一个线程能对其进行lock。多次lock后,必须执行相同次数的unlock才能解锁
    • 如果对一个变量进行lock操作,会清空所有工作内存中此变量的值,在执行引擎使用这个变量前,必须重新load或assign操作初始化变量的值
    • 如果一个变量没有被lock,就不能对其进行unlock操作。也不能unlock一个被其他线程锁住的变量
    • 对一个变量进行unlock操作之前,必须把此变量同步回主内存

    [final][https://www.jb51.net/article/157603.htm]作用

    [static][http://m.javaee.hqyj.com/java/1236.html]作用

二十三种设计模式

创建型模式:单例模式,工厂模式,抽象工厂模式,建造者模式,原型模式。

结构性模式:从程序的结构上实现松耦合,从而可以扩大整个类的结构

适配器模式,桥接模式,装饰模式,组合模式,外观模式,享元模式,代理模式。

行为模式:模板方法模式,命令模式,迭代器模式,观察者模式,中介者模式,备忘录模式,解释器模式,状态模式,策略模式,职责模链模式,访问者模式。

1. 单例模式

核心作用:保证一个类只有一个实例,并提供一个访问该实例的全局访问点

优点:

  • 只生产一个实例,减少了系统性能开销
  • 设置全局访问点,优化共享资源访问

5种单例模式:

1.1 饿汉式

线程安全,效率高,不能延时加载

package com.SingleModel;
//饿汉式
public class Demo01 {
    //1.私有构造器
    private Demo01(){}
    //2.类初始化时加载
    private static Demo01 instance = new Demo01();
    //3.提供获取对象获取方法
    public static Demo01 getInstance(){
        return instance;
    }
}

1.2 懒汉式

线程安全,效率不高(synchronized),能延时加载

package com.SingleModel;
//饿汉式
public class Demo02 {
    //1.私有构造器
    private Demo02(){}
    //2.类初始化时加载,不立刻加载该对象
    private static Demo02 instance;
    //3.提供获取对象获取方法,存在synchronized,效率低
    public static synchronized Demo02 getInstance(){
        if (instance == null){
            instance = new Demo02();
        }
        return instance;
    }
}

1.3 DCL懒汉式

由于JVM内部原因,偶尔出错,不建议使用

package com.SingleModel;
//DCL双重懒汉式
public class Demo03 {
    private static boolean flag = false;
    //1.私有构造器
    private Demo03(){
        //防止反射破坏
        if (false == false){
            flag = true;
        }else {
            throw new RuntimeException("Error");
        }
    }
    //2.类初始化时加载,不立刻加载该对象
    private static Demo03 instance;
    //3.提供获取对象获取方法,存在synchronized,效率低
    public static  Demo03 getInstance(){
        if (instance == null){
            synchronized (Demo03.class){
                if (instance == null){
                    instance = new Demo03();
                }
            }
        }
        return instance;
    }
}

1.4 饿汉式改进

线程安全,效率高,能延时加载

package com.SingleModel;

import java.lang.reflect.Constructor;

//静态内部类
public class Demo04 {
    private Demo04(){

    }
    private static class InnerClass{
        //final 保证了只有一个实例的存在
        private static final Demo04 instance = new Demo04();
    }
    public static Demo04 getInstance(){
        return InnerClass.instance;
    }
}
//反射机制:可以破坏单例
class Demo04Test{
    public static void main(String[] args) throws Exception {
        Demo04 instance = Demo04.getInstance();
        Constructor<Demo04> declaredConstructor = Demo04.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);

        Demo04 demo04 = declaredConstructor.newInstance();
        System.out.println(demo04==instance);
        System.out.println(demo04.hashCode());
        System.out.println(instance.hashCode());
    }
}

1.5 枚举单例

线程安全,效率高,不能延时加载

package com.SingleModel;
//枚举法:简单,安全,能防止反射破坏
public enum Demo05 {
    INSTANCE;

    public Demo05 getInstance(){
        return INSTANCE;
    }
}

class Demo05Test{
    public static void main(String[] args) {
        Demo05 instance = Demo05.INSTANCE;
        Demo05 instance2 = Demo05.INSTANCE;
        System.out.println(instance==instance2);
    }
}

2. 工厂模式

作用:实现创建者和调用者的分离

核心:实例化对象不使用new,用工厂方法代替,将选择实现类,创建对象统一管理和控制,从而将调用者跟我们的实现类解耦。

2.1 简单工厂模式

使用的多

package com.FactoryModel.simple;
//静态工厂模式
//增加一个新的产品,要修改代码,没实现开闭原则
public class CarFactory {
    public static void main(String[] args) {
        Car car = getCar("car1");
    }
    public static Car getCar(String car){
        if (car.equals("car1")){
            return new Car1();
        }else return null;
    }
}

interface Car{
    void name();
}
class Car1 implements Car{
    @Override
    public void name() {
        System.out.println("car1");
    }
}

2.2 工厂方法模式

package com.FactoryModel.simple;
//工厂方法模式
//用接口约束类
public class CarFactory {
    public static void main(String[] args) {
        Car car = new Car1Factory().getCar();
    }
}
interface Carfactory{
    Car getCar();
}
interface Car{
    void name();
}

class Car1 implements Car{
    @Override
    public void name() {
        System.out.println("car1");
    }
}

class Car1Factory implements Carfactory{

    @Override
    public Car getCar() {
        return new Car1();
    }
}

3. 抽象工厂模式

定义:抽象工厂模式提供了一个创建一系列相关或相互依赖对象的接口,无需指定他们具体的类。

应用场景:

  • 客户端不依赖与产品类实例如何被创建、实现等细节
  • 强调一系列相关的产品对象一起使用创建对象需要的大量重复代码
  • 提供一个产品类的库,所有的产品以同样的接口出现,从而使得客户端不依赖于具体的实现

优点:

  • 具体产品在应用的代码隔离,无需关心创建的细节
  • 将一系列的产品统一到一起创建

缺点:

  • 规定了所有可能被创建的产品集合,产品族中扩展产品困难
  • 增加了系统的抽象性和理解难度

4. 建造者模式

优点:

  • 产品建造和表示分离,实现解耦。
  • 将复杂产品的创建步骤分解在不同方法中,更清晰
  • 具体的建造者之间相互独立,利于扩展。

缺点:

  • 产品差异性大不适合。
  • 产品内部变化复杂,则需要定义许多建造者,系统变得庞大

应用场景:

  • 产品有复杂的内部结构,且产品对象具备共性
  • 隔离对象的创建和使用,通过相同的创造过程创造不同的对象
  • 适应于一个具有较多零件(属性)的产品(对象)的创建过程

5. 原型模式

应用:原型模式+工厂模式

浅克隆

 @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

深克隆

@Override
    protected Object clone() throws CloneNotSupportedException {
        //深克隆,将属性也克隆,此外序列化和反序列化也可以深克隆
        Object obj = super.clone();
        Video v = (Video) obj;
        v.date = (Date) this.date.clone();

        return obj;
    }

6. 适配器模式

作用:将一个类的接口转换

角色分析:

  1. 目标接口:客户端所期待的接口,可以是具体的或抽象的类,也可以是接口。
  2. 需要适配的类:需要适配的类或适配类。
  3. 适配器:通过包装一个需要适配的对象,把原接口转成目标接口
  • 转接口
package com.Adapter;
//接口转换器抽象实现
public interface NetToUSB {
    //处理请求,网线插上USB
    public void handleRequest();
}
  • 需要适配的类
package com.Adapter;

public class Adaptee {
    public void request(){
        System.out.println("连接上网");
    }
}

  • 适配器

    • 类适配器、单继承:只能适配具体的需要适配的类。
    package com.Adapter;
    //1. 继承(类继承,单继承)
    //真正的适配类,需要连接USB,连接网线
    public class Adapter1 extends Adaptee implements NetToUSB{
    
        @Override
        public void handleRequest() {
            super.request(); //可以上网了
        }
    }
    
    • 组合对象适配器:可以把多个不同的适配者适配到同一个目标
    package com.Adapter;
    //2. 组合,对象适配器
    public class Adapter2 implements NetToUSB{
        private Adaptee adaptee;
    
        public Adapter2(Adaptee adaptee) {
            this.adaptee = adaptee;
        }
    
    
        @Override
        public void handleRequest() {
            adaptee.request();
        }
    }
    
    
  • 接口2

package com.Adapter;

//客户端
public class Computer {
    //电脑需要连接转接器
    public void net(NetToUSB adapter){
        //需要一个转接头
        adapter.handleRequest();
    }

    public static void main(String[] args) {
        //电脑,适配器,网线
        //1.单继承
        Computer computer = new Computer();//电脑
        Adapter1 adapter1 = new Adapter1();//转接口
        //2.组合
        Computer computer1 = new Computer();//电脑
        Adaptee adaptee = new Adaptee();//网线
        Adapter2 adapter2 = new Adapter2(adaptee);//转接口

    }
}

7. 桥接模式

作用:将抽象部分与实现部分分类,是一种对象结构模式。

好处:

  • 减少了子类的个数,从而降低管理和维护成本
  • 提高系统扩展性,符合开闭原则,可以把两个变化的维度连接起来

劣势:

  • 抽象性难度增加
  • 需要正确识别两个独立变化的维度,具有局限性

应用场景:

  • 系统需要在构造的抽象化角色和具体化角色之间增加更多的灵活性。
  • 一个类需要存在两个独立变化的维度,且这两个维度都需要进行扩展。
  • 不希望使用继承或多层次继承导致系统类的个数急剧增加的系统。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wLhnty6e-1582198523004)(C:\Users\zzc19941219\AppData\Roaming\Typora\typora-user-images\1582187920250.png)]

8. 代理模式

是SpringAOP的底层

代理模式分类:

  • 静态代理
  • 动态代理

8.1 静态代理

角色分析:

  • 抽象角色:一般会使用接口或抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理后会做一些附属操作
  • 客人:访问代理对象的人

代码步骤:

  1. 接口

    package com.Proxy.demo01;
    //租房
    public interface Rent {
        public void rent();
    }
    
  2. 真实角色

    package com.Proxy.demo01;
    //房东
    public class Host implements Rent{
        @Override
        public void rent() {
            System.out.println("房东要出租房子");
        }
    }
    
  3. 代理角色

    package com.Proxy.demo01;
    
    public class Proxy implements Rent {
        private Host host;
    
        public Proxy(){
    
        }
    
        public Proxy(Host host) {
            seeHouse();
            this.host = host;
        }
    
        @Override
        public void rent() {
            host.rent();
        }
        //看房
        public void seeHouse(){
            System.out.println("带你看房");
        }
        //收中介费
        public void fara(){
            System.out.println("收中介费费");
        }
    }
    
  4. 客户端访问角色

    package com.Proxy.demo01;
    
    public class Client {
        public static void main(String[] args) {
            Host host = new Host();
            Proxy proxy = new Proxy(host);
            proxy.rent();
        }
    }
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fXo3Xh4o-1582198523005)(C:\Users\zzc19941219\AppData\Roaming\Typora\typora-user-images\1582195591259.png)]

好处:

  • 可以使真实角色的操作更加纯粹,不用去关注一些公共业务
  • 公共交给代理角色去做,实现业务分工
  • 公共业务扩展时,集中管理

缺点:

  • 一个真实角色就会产生一个代理角色,开发效率会降低。

静态代理加深理解:

package com.Proxy.demo02;

public class UserServiceProxy implements UserService {

    private UserServiceImp userService;

    public void setUserService(UserServiceImp userService) {
        this.userService = userService;
    }

    @Override
    public void add() {
        log("add");
        userService.add();
    }

    @Override
    public void delete() {
        log("delete");
        userService.delete();
    }

    @Override
    public void update() {
        log("update");
        userService.update();
    }

    @Override
    public void query() {
        log("query");
        userService.query();
    }
    //日志方法
    public void log(String msg){
        System.out.println("使用了"+msg+"方法");
    }
}
发布了1 篇原创文章 · 获赞 0 · 访问量 19

猜你喜欢

转载自blog.csdn.net/weixin_38534395/article/details/104416629
今日推荐