【JAVA黑马程序员笔记】四 P314到P384(特殊流、多线程编程、网络编程模块、lambda表达式、接口组成更新、方法引用、函数式接口)

【JAVA黑马程序员笔记】四 P314到P384(特殊流、多线程编程、网络编程模块、lambda表达式、接口组成更新、方法引用、函数式接口),第1张

【JAVA黑马程序员笔记】四 P314到P384(特殊流、多线程编程、网络编程模块、lambda表达式、接口组成更新、方法引用、函数式接口) P314-315 字节/符打印流
        PrintStream ps = new PrintStream("test.txt");

        //使用字节输出流的方法
        ps.write(97);
        // 使用特有方法写数据
        ps.print(97); //write
        ps.println("hello,world");



        ps.close();
    }
        PrintWriter pw = new PrintWriter(new FileWriter("test"),true);

        pw.write("hello");
        pw.flush();
        pw.println("hello");
        pw.println("world");



        pw.close();

P317-318 对象序列/反序列流
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("test.txt"));

        Student s1 = new Student("aaa",30);

        oos.writeObject(s1); //把object给序列化到文件中


        oos.close();
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("test.txt"));

        Object obj = ois.readObject();

        Student s = (Student) obj;
        System.out.println(s.getAge()+","+s.getName());


        ois.close();
P319 serialVersionUID&transient

用对象系列化了一个对象后,如果我们修改了对象所属的类文件,对去数据会出现InvalidClassException的异常,所以,为了防止出问题,给这个对象所属的类加一个值:private static final long serialVersionUID = …,如果不期望某个属性参与序列化过程,则在这个属性的声明的时候,private transient int age,使用transient声明一下。

P320 Properties作为Map集合使用

Properties是一个Map体系的集合类,可以保存到流中或从流中加载。

        Properties prop = new Properties();

        prop.put("aaa","111");
        prop.put("bbb","222");
        prop.put("ccc","333");

        Set keySet = prop.keySet();
        for(Object key :keySet)
        {
            Object value = prop.get(key);
            System.out.println(key+":"+value);
        }
 

Properties作为集合的特有方法

        Properties prop = new Properties();

        prop.setProperty("aaa","111");
        prop.setProperty("bbb","222");
        prop.setProperty("ccc","333");

        //根据键得到值
        System.out.println(prop.getProperty("aaa"));
        System.out.println(prop);

        // 得到键
        Set names = prop.stringPropertyNames();
        for(String key:names){
            System.out.println(key);
            String value = prop.getProperty(key);
            System.out.println(key+","+value);

        }

Properties和IO流相结合的方法

   public static void main(String[] args) throws IOException {
        // 把集合中的数据保存到文件
        myStore();
        //把文件中的数据加载到集合
        myLoad();

    }

    private static void myLoad() throws IOException {
        Properties prop = new Properties();
        FileReader fr = new FileReader("test.txt");
        prop.load(fr);
        fr.close();
        System.out.println(prop);
    }


    private static void myStore() throws IOException {
        Properties prop = new Properties();

        prop.setProperty("aaa","111");
        prop.setProperty("bbb","222");
        prop.setProperty("ccc","333");
        FileWriter fw = new FileWriter("test.txt");

        prop.store(fw,null); // null则不添加描述信息


        fw.close();



    }
P324 进程和线程

进程:是正在运行的程序

  1. 是系统进行资源分配和调用的独立单位。
  2. 每一个进程都有它自己的内存空间和系统资源。

线程:是进程中的单个顺序控制流,是一条执行路径

  1. 单线程:一个进程如果只有一条执行路径,则称为单线程程序。
  2. 多线程:一个进程如果有多条执行路径,则称为多线程程序。
P325 多线程的实现方式

在MyThread的类中:
Thread有默认名称,可以使用getName,即使子类没有name的成员,所以也可以在主函数中使用setName去重新命名线程的名字

public class MyThread extends Thread{
    MyThread(){

    }
    MyThread(String name)
    {
        super(name);
    }
    @Override
    public void run() {
       for(int i=0;i<100;++i){
           System.out.println (getName()+ ":" + i);
       }
    }
}

在主函数中:

        MyThread my1 = new MyThread("my1");
        MyThread my2 = new MyThread("my2");
        my1.start();
        my2.start();

System.out.println(Thread.currentThread().getName());

注意主函数中使用的是有参构造方法,其实是对Thread的name进行了赋值。

==System.out.println(Thread.currentThread().getName());==获得当前正在执行的线程的名称。

P327 线程调度(线程优先级)

      //返回线程的优先级,也可以看出来线程的优先级默认是5,最大10,最小1
        System.out.println(my1.getPriority());
        System.out.println(my2.getPriority());
        System.out.println(Thread.MAX_PRIORITY);
        System.out.println(Thread.MIN_PRIORITY);
        System.out.println(Thread.NORM_PRIORITY);
        my1.setPriority(10);
        my2.setPriority(5);
        my3.setPriority(1);
P328 线程控制


sleep在重写run函数中使用:

 @Override
    public void run() {
       for(int i=0;i<100;++i){
           System.out.println (getName()+ ":" + i);
           try{
               Thread.sleep(1000);
           }catch (InterruptedException e){
               e.printStackTrace();
           }
       }
    }

join在主函数中使用:

        my1.start();
        try {
            my1.join(); //阻塞,直到my1执行完,才开始my2 my3
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        my2.start();
        my3.start();

设置守护线程

        Thread.currentThread().setName("Main");

        my1.setDaemon(true);
        my2.setDaemon(true);

当主线程结束时,则my1,my2页结束。

P329 线程声明周期

d幕说这是丁字裤图。。

P330 实现Runnable接口的方式实现多进程

注意实现Runnable的类就不能使用getName()的方法了,但是可以:

System.out.println(Thread.currentThread().getName() + ":" + i);

类中:

public class MyRunnable implements Runnable{

    @Override
    public void run() {
        for(int i=0;i<100;++i){
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}

主函数中:

       MyRunnable my =  new MyRunnable();
       
       Thread t1 = new Thread(my);
       Thread t2 = new Thread(my);
		t1.start();
		t2.start();
P333 同步代码块解决数据安全的问题

同步代码块通过使用以下的方式实现,任意对象可以看成是一把锁
好处:解决了多线程中的数据安全的问题
坏处:线程很多时,每个线程都会判断同步上的锁,这很耗费资源,无形中降低了程序的效率。

synchronized(任意对象){


}
  @Override
    public void run() {

     while(true){
         synchronized (obj){

             if (tickets > 0) {
                 try {
                     Thread.sleep(100);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
                 System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
                 tickets--;

             }


         }


    }
    }
P334 同步方法解决数据安全问题

此时方法的锁是this的锁,也就是相当于synchronized(this){}

public synchronized 返回值 方法名(){


}
335 线程安全的类

当使用多线程时,应该使用下面的类

查看他们的源码有没有被synchronized修饰

   StringBuffer sb = new StringBuffer();
        StringBuffer sb2 = new StringBuffer();

        Vector v = new Vector();
        ArrayList array = new ArrayList();

        Hashtable ht = new Hashtable();
        HashMap hm = new HashMap();


        List list = Collections.synchronizedList(new ArrayList());
        
P336 Lock锁

    private Lock lock = new ReentrantLock();
    @Override
    public void run() {


        while(true){
            try {
                lock.lock();
                if (tickets > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
                    tickets--;

                }
            }finally {
                lock.unlock(); 
            }
               




        }
    }
P337生产者与消费者


当方法内部使用wait()方法时,注意给方法加上synchronized关键字

P339 网络编程模块

计算机网络:指将地理位置不同的具有独立功能的多态计算机及其外部设备,通过通信线路连接起来,在网络 *** 作系统,网络管理软件及网络通信协议的管理协调下,实现资源共享和信息传递的计算机系统。
网络编程:指再网络通信协议下,实现网络互联的不同计算机上运行的程序间可以进行数据交换。

网络编程三要素

IP地址

InterAddress的使用

可以通过主机名或者IP地址来获得,这里IP地址我随便弄了个,应该是自己电脑的。

        InetAddress address = InetAddress.getByName("Phalange");
        //InetAddress address = InetAddress.getByName("88.22.88.88");
        String name = address.getHostName();
        String ip = address.getHostAddress();

        System.out.println("主机名:" + name);
        System.out.println("IP address " + ip);

端口

协议


UDP通信原理

UDP发送数据

       DatagramSocket ds = new DatagramSocket();
        byte[] bys="hello,upd,i am coming..".getBytes(StandardCharsets.UTF_8);
        //int length = bys.length;
        //InetAddress address = InetAddress.getByName("Phalange");
        //int port = 10086;
        //DatagramPacket dp = new DatagramPacket(bys,length,address,port);
        DatagramPacket  dp = new DatagramPacket(bys, bys.length, InetAddress.getByName("Phalange"), 10086);
        ds.send(dp);



        ds.close();

保证发送的数据和接收的数据是一个端口的。
UDP接收数据

    DatagramSocket ds = new DatagramSocket(10086);



        byte[] bys = new byte[1024];
        DatagramPacket dp = new DatagramPacket(bys, bys.length);



        ds.receive(dp);
        //解析数据包
        byte[] datas = dp.getData();
        int len = dp.getLength();
        String dataString = new String(datas,0,len);
        System.out.println(dataString);
        ds.close();

TCP通讯原理

TCP发送数据

      Socket s = new Socket(InetAddress.getByName("Phalange"),10000);

        //Socket s = new Socket("192.162.1.1",10000);
        OutputStream os = s.getOutputStream();
        os.write("hello,tcp,iam coming".getBytes(StandardCharsets.UTF_8));

        s.close();

TCP接收数据

        ServerSocket ss = new ServerSocket(10000);
        Socket s = ss.accept();

        InputStream is = s.getInputStream();

        byte[] bys = new byte[1024];
        int len = is.read(bys);
        String data = new String(bys,0,len);
        System.out.println("data is :"+data);

        s.close();
        ss.close();

TCP练习
Socket.shotdownOutput(); // 发送一个结束的标记

P355 lambda表达式

概述

小例子

        new Thread(() -> {
            System.out.println("多线程启动了");
        }).start();

lambda表达式的标准格式

练习:抽象方法是三种实现

        useEatable(new EatableImpl());

        useEatable(new Eatable(){
            @Override
            public void eat() {
                System.out.println("i am eat...");
            }
        });
        // lambda
        useEatable(()->{
            System.out.println("i am eat....");
        });

有返回值的重写

    public static void main(String[] args) {
        useAddalbe((int x,int y)->{
            return x+y;
        });



    }
    public static void useAddalbe(Addable a){
        int sum  = a.add(10,10);
        System.out.println(sum);
    }

lambda省略规则

   // 参数的类型可以省略
        useAddalbe((x,y)->{
            return x+y;
        });
        // 如果只有一个参数,可以省略小括号;如果只有一行代码,可以省略大括号和分号,
        //return 也可以省略

        useFlyable(s-> System.out.println(s));
        useAddalbe((x,y)->x+y);

lambda表达式的注意事项

一定要注意是接口!!并且有且仅有一个抽象方法!!

lambda表达式和匿名内部类别

P363 接口组成更新


接口中默认方法

接口中的静态方法

接口中的私有方法

P367 方法引用

体验小例子

        usePrintable(s-> System.out.println(s));


        //方法引用符号::
        //可推到的就是课省略的
        usePrintable(System.out::println);

== 方法引用符==

::为方法引用符,而他所在的表达式被称为方法引用。

引用类方法
引用类方法,其实就是引用类的静态方法

== 引用对象的实例方法==

使用PrintString这个类已经实现的方法来实现接口

PrintString ps = new PrintString();
usePrinter(ps::printUpper);

Lambda表达式被对象的实例方法替代的时候,他的形式参数全部传递给该方法作为参数。

引用类的实例方法

useMyString(String::substring);

Lambda表达式被类的实例方法替代的时候,他的第一个参数作为调动着,其他的参数全部传递给该方法作为参数。

引用构造器

     useStudentBuilder((name,age)->{
            return new Student(name,age);
        });
        useStudentBuilder(Student::new);

Lambda表达式被构造器代替的时候,他的全部参数被传给构造器作为参数。

函数式接口
函数式接口:有且仅有一个抽象方法的接口。

被@FunctionalInterface注解一下最好。

@FunctionalInterface
public interface FuncInterface {
    void show();
}

函数式接口作为方法参数

函数式接口作为方法的返回值

P376 常用的函数式接口

Supplier接口

    public static void main(String[] args) {
       String s =  getString(()->{
            return "hello,java";
        });
       Integer i = getInteger(()->30);
        System.out.println(i);
        System.out.println(s);

    }
    private static Integer getInteger(Supplier sup){
        return sup.get();
    }
    private static String getString(Supplier sup){
        return sup.get();
    }

Consumer接口

andThen方法

  public static void main(String[] args) {

        operatorString("abbcccc",(String s)-> System.out.println(s));
        operatorString("abcdefg",(String s)->{
            System.out.println(new StringBuilder(s).reverse().toString());
        });
        operatorString("aaa",s-> System.out.println(s),s->System.out.println(new StringBuilder(s).reverse().toString()));

    }

    private static void operatorString(String name, Consumer com1,Consumer com2){
       // com1.accept(name);
       // com2.accept(name);
        com1.andThen(com2).accept(name);
    }

    private static void operatorString(String name, Consumer com){
        com.accept(name);
    }

Predicate接口

.negate方法对test方法的结果做了一个逻辑非的 *** 作。

   public static void main(String[] args) {

        //boolean b = checkString("hello",(String s)->s.length()>8);
        //System.out.println(b);
        //boolean b2 = checkString("hello,world",s -> s.length()>8);
        //System.out.println(b2);

        boolean b3 = checkString("hello",s->s.length()>8,s->s.length()<15);
        System.out.println(b3);


    }
    private static boolean checkString(String s, Predicate pre1,Predicate pre2){
        //boolean b1 = pre1.test(s);
        //boolean b2 = pre2.test(s);
        //boolean b3 = b1 && b2;
        //return b3;

        //return pre1.and(pre2).test(s);
        return pre1.or(pre2).test(s);
    }
    private static boolean checkString(String s, Predicate pre){
        return pre.negate().test(s);

    }

Function接口

 public static void main(String[] args) {

        convert("100",s->Integer.parseInt(s));
        convert("100",Integer::parseInt);
        convert(100,i->String.valueOf(i+400));
        convert("100",Integer::parseInt,i->String.valueOf(i+100));
    }

    private static void convert(String s, Function fun){
        int i = fun.apply(s);
        System.out.println(i);
    }
    private static void convert(int i,Function fun){
        String s = fun.apply(i);
        System.out.println(s);
    }

    private static void convert(String s,Function fun1,Function fun2){
        //Integer i = fun1.apply(s);
        //String ss = fun2.apply(i);
        String ss = fun1.andThen(fun2).apply(s);
        System.out.println(ss);
    }

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5671866.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)