Java学习进阶1

Java 学习进阶

从这里开始是Java的进阶内容:

Object类的方法:
【toString】方法
toString方法是Object类的方法,因为Object类是所有类的超类,故所有类都继承了Object类;自己定义的类也是。
返回值是一个字符串,对象名.toString();打印出来是这个对象地址(在这个类没有重写toString方法时)通过Alt+Insert可以直接重写一个类中的toString方法
【equals】方法
判断是否相等,Object里面的内容是:return this==obj;(obj是参数列表里面的参数)
“==”基本变量是比较的里面的值,引用类型里面比较的是里面的地址
(别忘了,使用向上转型时,一种是在创建对象时使用父类指向子类的对象的引用;第二种是将一个子类对象传参给父类参数列表时发生的转换;这个东西的向下转型是必须的;和那个子类重写父类方法后,可以使用父类对象“调用”子类方法不一样)
这个equals方法在Objects类里面也有,这是个静态类,直接用类名访问。Object类和String类型覆写的子类都会在当前对象(前面的那个对象)是空指针时抛出异常,而Objects就不会。
【Date】类:
这个类是关于时间及其操作的一个类,里面装的是时间获取,操作有关函数。
首先来了解System.currentTimeMillis()方法,System是一个final类。这个方法返回的是由毫秒零点到现在为止的过去的毫秒数。
Date类:构造方法:Date(); 这个是最基本的构造方法,使用这个进行构造对象时,直接打印对象会输出按照默认时间格式的一个时间序列。
Date(long n);这个构造方法是在后面传入一个long型数,返回的是经过n毫秒后的默认格式时间序列。
.getTime();方法是和System.currentTimeMillis()一样。
【Format】:他是抽象类,有子类:
【DateFormat】:也是抽象类,有子类:
SimpleDateFormat,这个东西光是管转型的,也就是现在构造方法里面传递给他一个字符串,字符串是一个模式(下面给怎么写),
之后调用里面的parse还有format方法,就可以完成Date和String型之间的转换。
format(Date d);里面传一个日期格式,可以返回一个字符串,这个字符串符合相应的模式。
parse(String str)throw parseException;这个字符串作为参数,抛出异常,返回Date日期。
年月日时分秒:y M d H m s

【Calender】
这个类是个抽象类,它的对象由其方法getInstance();获取Calender cale=Calender.getInstance();
常用的成员方法:get(int field)返回给定的日历字段的值
set(int field,int value)设置日历字段的值
add(int field, int amount)给指定的日历字段增加或减去指定的时间量
getTime()返回现在的Calender转换为的Date对象
Calender里面的成员变量很多都是final类型的静态变量,如:
public static final int YEAR = 1;
这样的,int field即是使用它们…
比如:set(YEAR, 2020);就是把年份设置为2020年

【System】类
currentTimeMillis:静态方法,直接调用,返回以毫秒为单位的系统时间。
arraycopy(原数组名,原数组位置,目标数组名,目标数组位置,位数);拷贝数组的方法,静态方法
【StringBuilder】类
是关于字符串缓冲区的类,用于提高字符串参与时的运行效率。
字符串在计算机底层是一个final定义的字符串,所以其值无法修改
普通的字符串相加会生成多个字符串,占地方。这个不会,他是一个byte[] value=new byte[16];
数组,节省空间。
主要方法:append方法,非静态的,要用对象的。这个方法的参数列表重载了很多种(输入什么都会被转换成字符串类型的…(变量会自动识别的哦))。主要是在字符串中添加数据。返回值是this,这个对象(地址)本身。(一般不用到返回值)
构造方法,就是StringBuilder();这样创建的是一个空的字符串。构造方法里面可以加入字符串,这样就赋予了初始值。
toString方法:非静态的,主要功能是将一个字符串缓冲区类型转换成String类型,返回值即为String类型。
【包装类】
比如Integer类,这个是lang包下的类,无需导包;目的是将一个基本数据类型进行操作。
导入数据的方法:
1.构造方法:Integer(int value/String numstr);(导入字符串时一定要注意格式)
2.静态方法:Integer.valueOf(int value/String numstr),返回的是Integer包装类型,和构造方法一样
3.成员方法:inter.intValue();将Integer类型转换为int类型(其实是 对应类型包装类实例(对象).相应的数据类型Value(); 这样才能有效转换为基本数据类型,不然的话转换过去之后会发生类型转换,)
4.包装类和字符串之间的转换:
1.由数据转换为字符串:
[1].一般使用的都是:数据+"";自动转换
[2].包装类中有两个toString的方法,一个是静态的,把参数放括号里面;另一个是成员方法直接调用转换var接收。包装类里面的静态方法.XXXValue可以将字符串变成对应的XXX类型,就是上面步骤的反过来。
[3].String类中的静态方法valueOf也可以将里面的数据转换成String类型。

XXXparse可以将字符串类型转换为相应的数据类型,是普通数据类型。

【集合与接口】:
Collection是所有单列集合(集合接口不使用泛型将默认是Object)的父接口,使用最上层的集合Collection进行构造集合,可以进行多态的使用,而集合分为List和Set两类;这就可以使得改动更加方便。
(关系啦就是ArrayList是List接口的实现类,而List接口又是继承了Collection接口,所以可以使用多态进行向上转型赋值)
Collection中的方法,在这两个集合种类里面是通用的,toArray() 方法将这个集合转化成一个数组,
Collection这个集合为父接口定义的集合是没有索引的,所以要是想得到里面的数据就要用toArray来转换成Object数组,或者是使用迭代器:
【迭代器】:Iterator
使用Iterator迭代器进行不同的集合的通用迭代。
Collection生成实现类对象collection=new ArrayList<>();(多态)
【先将集合里面填充上数据,然后再进行生成迭代器!】:
Iterator it=collection.iterator();
这个得到的是Iterator的实现类的对象,实质上是个多态。
主要方法:hasNext();判断指针的下一个是否有内容是则返回true 否则返回false
next();直接返回指针的下一个内容。(如果下一位已经没有内容了,则会出现Exception)

(两个元素都相同的时候是指的equals和hashcode都相同的时候)

【增强for循环和原理】
首先,Iterator和Collection都是接口,
foreach是增强型for循环的全称,其原理是iterator,这也限定了它只能对Collection和数组进行遍历
Collection的泛型不同时创建出来的实现类(多态实现类)之间不能使用所谓的向下转型进行转换
增强型for循环的结构:for(数据类型 随便拟定一个变量名:要遍历的集合或者是数组)
【泛型】
就是,在不知道要用什么类型的时候就写上这个的类型,常用于类,集合,方法中。
使用不带有泛型的Collection集合的时候会默认类型为Object,这个类型可以接受所有的包装类,但是不推荐使用这种写法因为这很不安全。
不要在方法传递参数的时候用好像可以进行多态的方法对带有泛型的集合进行传递,比如把list传给list,因为泛型没有继承的概念。

1.在类中使用泛型:在类的名字后面直接,然后到类体中使用;这样创建的类要么在创建对象使用的时候被确定,要么在子类继承他的时候在子类名字后面指定<具体类型> ,在创建时就自动被重写为相应的类型然后正常使用。
2.在方法中使用泛型:修饰符 返回值类型 方法名(){return} 这样用,要是想要正常使用泛型的话,就要把它写在参数列表里,不然的话你会找不到地方给它赋值,很麻烦,使用的时候用相应的类型替换掉位置即可。
3.接口中使用泛型,和类中差不多,但是要注意用接口继承接口,或者是用类实现接口时指定类型的话比类中的子类指定类型来得有意义。如果是接口继承接口,在其中一步泛型确定后,接下来继承或是重写都无需再提到泛型,当成普通接口重写就可以。
【泛型通配符】
泛型通配符使用在方法的参数列表中,主要是为了接收不确定类型的泛型类,符号为<?>,代替原有的泛型的位置;
使用泛型通配符进行接收的话,虽然说直接使用Object进行接收是不允许的,但是要是使用了泛型通配符进行接受的话,其内部还是使用的Object类型进行接收;泛型通配符只允许出现在方法的参数列表中。
通配符的上界限:<? extends 一个类>:必须传递进来的类是这个类的子类;
通配符的下界限:<? super 一个类>:必须传递进来的类是这个类的父类;
【List接口】
是继承了Collection接口的子接口,其下有ArrayList,LinkedList,Vecter等多个实现类;
常用:add(index,element); or add(element);//get(index);//remove(index);//set(index,element);用指定元素替换这个索引上的元素;SubList返回一个小的替身,对其进行修改会对本体造成影响。
【ArrayList】
底部是数组结构,故查询快,增删慢;另外,它和Vecter不同,它的效率更高,是多线程的。
【LinkedList】
底部是链表结构,故查询慢,增删快;另外,它和Vecter不同,它的效率更高,是多线程的。
常用:头接法:addFirst(E e);/push(E e);//尾接法addLast(E e);/add(E e);//返回头元素尾元素getFirst();/getLast();//移除头元素尾元素并且返回它removeFirst();/removeLast();//pop();->相当于removeFirst();

【Set】【HashSet】(clear,isEmpty,remove(后面加元素Object))这是一个比较特殊的集合,底层是哈希表结构,导致它的查询速度非常快;同时,HashSet实现这个接口,Set里面不能有重复的元素,而且使用add加入进去的元素在取出时不是原序的。
这个东西的add当加入进去的东西重复时,会返回一个false 不重复返回一个true
(Set也可以使用迭代器遍历,而且补充一个点,所有的使用迭代器的集合,都可以使用增强for循环进行遍历)
[Hash值]:是由物理地址经由演算变过来的,不是真的物理地址;Object类中的.hashCode();可以直接得到一个类的哈希不同数据的哈希值在内存中是不同的,但是相同内容的字符串的哈希值相同,这是因为(相同内容的字符串在内存中只有一份。)哈希值是由字符串转换过来的
哈希表在jdk1.8之前是数组加链表的结构,后来换成了数组加链表加红黑树的结构,目的是加速查询速度。首先把相同哈希值的元素放到一个空间内,然后挂到数组下面,先查询哈希值,后顺着链表或者红黑树查具体数据。
Set储存不重复的原理:在add时,先后调用被存储对象的hashCode();和equals();这两个方法,全相等则会排除。如果不想使用默认的判断法,就要重写存储对象类的hashCode和equals方法。(如果是一个自定义类中,则会自动生成时按照各成员变量的内容一致与否来判断是否相等)
附一个“==”和“equals();”的比较
String x = “abc”;
String y = “abc”; //指向同一个引用
String z = new String(“abc”); //开辟了新的空间
System.out.println(x==y);     // true
System.out.println(x==z);      // false
System.out.println(x.equals(y));   // true
System.out.println(x.equals(z));   // true

代码解读:因为 x 和 y 指向的是同一个引用,所以
== 也是 true,而 new String()方法则重写开辟了内存空间,所以 == 结果为 false,而 equals 比较的一直是值,所以结果都为 true。
String和Integer等的类吧equals();改成了值比较,而它本来应该是引用比较。
【LinkedHashSet】有顺序,不同于无序的HashSet。因为它的内部还有一个链表。其他不变
【可变参数】在一个参数列表中只能有一个,而且要写在最后面。
,int…nums)这样定义,实质上是把传进来的参数归成了一个数组,正常按数组操作即可。
,Object…objects)叫作终极可变参数。
【Collections工具类】
shuffle(集合);打乱元素:参数是List类型
reverse(集合);逆序:参数是List类型
binarySearch(集合,元素)二分查找。返回序号
addAll(集合,想加进去的元素)
sort(自动升序排序集合)//非自定义类型
sort(自定义类型集合)//必须实现Comparable<当前类>这个带有泛型的接口
//并且在类中重写compareTo()方法:return this.getXX()-o.getXX();是升序
//return o.getXX()-this.getXX();是降序
sort(双参数排序)//前一个参数是要排序的集合,后面的参数是一个Comparator的对象,使用时现场定义匿名内部类即可。o1-o2是升序,o2-o1是降序。
(return返回值在元素相等时是0,此时用一个int接受它并且通过if判断可以进行二重排序-拓展)
这几个排序都是针对List的,跟Set没关系。。
【Queue】
PriorityQueue是他的一个实现类,同时LinkedList也是他的一个实现类;加入元素用add或者offer;peek:“弹出”当前的队首元素并且不删除,使用remove也可以进行删除。
【Map】
Map是个双列集合:有两个泛型<K,V>:key和value;

  1. Map集合是一个双列集合, 一个元素包含两个值
  2. Map集合中的元素,key和value的数据类型可以相同, 也可以不同
  3. Map集合中的元素,key是不允许重复的,value可以重复的
  4. Map集合中的元素,key和value是一一对应的
    这个接口下的实现类:【HashMap】;底层也是哈希表,这个东西和
    HashMap底下的一个子类:LinkedHashMap():是有顺序的哈希图
    常用方法:put(K,V)
    get(K) remove(K/V);containsKey();containsValue();这两个东西针对给定的KV进行查询,如果没有查到所给的值,返回false查到东西返回true。
    这几个方法都是在有正常返回值的时候返回对应的V值,但是如果得不到正常的返回值,比如第一个put(K,V)的K是首次进去的K,那么就返回null。或者get,remove找不到对应的KV,也返回null
    comtainsKey(Object key),判断这个图中是否有对应的key,按照布尔类型返回。
    【遍历Map】的方法稍微有点不同:
  5. map.keySet()返回一个只有其key的Set集合,使用迭代器或者增强for循环进行遍历。同时,也要借助map.get(K)进行调用value
  6. Map.Entry<K,V>是Map的一个子接口,这里面有两个常用的方法getKey() 和 getValue(); 对应的Map及子类的对象使用entrySet();可以返回一个子接口entry对象,从而用这两个方法遍历。
    3.使用自定义类型作为键值时,需要自己重写对应类中的hashCode()和equals();方法。
    【LinkedHashMap】有顺序,put按顺序来,是HashMap类的一个子类
    【Hashtable】是在jdk1.0的原始HashMap,是Map的一个子类,现已被取代;它是单线程的。他不允许有null键和null值存在。但是它的子类Properties依然在使用,并且和IO流相关
    【.of】是JDK1.9的新特性,是List Set Map的一个静态方法,返回一个不可改变的对应的集合,参数是多参数,Set.of()这里面的元素不能重复;Map.of()这里面是一个K一个V,K也都不能重复
    IllegalArgumentException警告
    【throw】【throws】
    程序会抛出异常,可以是平时不用咱们管理,自动抛出的运行时异常;也可以是自己添加的异常。
    当运行到某些语句时,使用throw 异常类(异常报告);便可以抛出异常,
    此时,对应的外部方法需要throws 异常类(或者他的父类),如果又有语句调用了这个方法,那么它也要抛出,最后方法不调用或是被main抛出,由JVM处理
    RunTimeException是运行时异常,这个东西可以不手动抛出或处理;放在方法中时,只要throw new RunTimeException(“要报错的语言”),可以直接让JVM处理。(中断处理,报错)
    (其实并不是非要throw然后new 异常,只要语句中有异常产生,这个东西就默认写了,可以直接在方法处抛出throws 异常类名)
    然后是手动创建异常类,需要继承Exception父类,然后创建两个构造方法,含参的那个是字符串类型,并且调用父类构造方法super(这是传进来的字符串参数);就完成了。
    【try…catch】
    就是针对有可能出现异常的语句进行try,然后在catch中处理,catch后面亦可以加上finally{},当try中的异常出现时,就不会再往后走了,直接从trycatch后面执行,但是如果有finally,不管try中是否异常都会执行finally中的语句;
    同时,catch的顺序需要子类异常在上,父类在下,因为父类可捕捉子类异常
    子类继承父类进行方法重写,需要保证子父类的抛出异常一致,子类重写的方法如果有异常,需要trycatch处理

【线程】:是指的CPU处理应用的路径条数
线程有两个调度:1.分时调度:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间,
2.抢占式调度:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个;
java使用的是抢占式调度
线程的使用首先要求创建一个继承于Thread类的子类,并且通过这个方法来重写run方法(此时要在run方法中加入线程命令),在其他的方法中(main)创建这个子类的实现类并且调用其中的start方法,
start方法实际上就是执行本对象对应的线程子类的run();
线程的常用方法:
[1]getName();放在run里面,返回当前线程的名字,是String类型
[2]currentTimeThread();是个Thread里面的静态方法:返回当前线程的Thread类型的对象。(禁止套娃,会报错)
[3]setName();,成员方法,可以更改该线程名字,或者创建含参String构造方法,传递参数到super()中,可以请求父类给他改名。
[4]sleep();休眠,是Thread类中的静态方法;往里面传入毫秒值,(sleep好像自带错误,需要使用try…catch直接处理一下才能用)
另外一种创建线程的方法:创建一个实现了Runnable()接口的类,使得它重写其中的run()抽象方法。然后把实现类的对象传到Thread()构造方法中,创建一个Thread对象接受,这个对象即是新线程对象。改名时要对这个对象.setName();而且在重写run()时不能使用getName();获取名字,只能使用Thread.currentTimeThread.getName();获取名字;
当然,使用匿名内部类的方法也是可以的。
线程本身实际上是new出来的Thread(及子类)对象,不是创建的Runnable重写或是创建的Thread子类本身。每次new一个才会使线程增加1条
【共享资源】:多个线程想要处理共同的一部分资源,那就要创建Runnable()实现类时只创建一个
但是使用这种方式的时候会出现线程安全问题,造成代码执行混乱。要进行处理:
在实现类里面创建一个任意地对象,比如Object obj=new Object();
使用同步代码块进行线程锁:synchronized(obj){这里面放入涉及到共享资源的代码}
然后进行多线程操作时,像:一个票卖好几遍,卖出了不存在的票,这样的问题就会消失,造成:一核有难,多核围观的场面。
使用线程锁,除了创建同步代码块,还可以创建同步方法:
public synchronized void Method01(){内部是涉及到共享资源的代码}
这种方式其实相当于使用了线程锁,只是用于锁定的对象是本类的实现对象this
public void Method01(){
synchronized(this){代码}
}
相当于这个,除此之外,还有静态的这种方法,但是它使用的是这个Runnable实现类(假设为RunnableImpl)的RunnableImpl.class这也是一个对象。
[4].使用lock()方法对线程直接加锁,Lock接口下面有实现类ReentrantLock,在成员位置创建ReentrantLock的对象然后在开始的地方调用lock();在结束的地方调用unlock();可以保证线程安全。
(建议:将unlock();放到finally块里面,(是为了安全))
线程自身会有很多不同的状态,比如运行状态,休眠状态,死亡状态,
休眠状态:使用wait();进行线程休眠,这个语句要写在synchronized(obj)里面,需要处理错误,使用的锁对象是obj,因为它是Object的一个成员方法,obj.wait();同时,进行休眠之后这个线程暂停,归还线程锁,并且使用另一个obj.notify();来唤醒他,这两个锁必须是一个Object对象锁。
然后是notifyAll();这个可以唤醒所有的使用当前锁的沉睡线程。
【线程间通信】
wait和notify这两个方法都必须在同步代码块或者同步函数中被调用,因为它们必须是调用同一个锁对象,只有同步是使用锁的。
【线程池】
使用线程池的工厂类Executors里边提供的静态方法newFixedThreadPool来生产一个指定线程数量的线程池;创建一个实现类来实现Runnable接口,重写run方法,设置线程任务;调用ExecutorSevirce中的方法submit来传递线程任务,开启线程,执行run方法;(调用Executor的shutdown销毁线程池)
Executors.newFixedThreadPool()这个是主要方法,里面放的参数是内含的线程数量,返回值是ExecutorSevirce接口的一个实现类对象,但是要求使用ExecutorSevirce 接口接收(类似于多态),这个接口的(多态)对象接受之后使用es.submit()里面传参为一个Runnable实现类对象,通过这个submit方法直接start这个线程任务。也就是说将一个任务直接分配给里面的空闲线程。
【Lambda表达式】
是新特性,主要是用来简化 由于定义接口抽象方法引起的 重写时的 匿名内部类 的写法
使用的标准格式:()->{}
其中:()中的是参数列表,{}里的是方法体;这个使用有限制条件:
1.只能是在接口的匿名内部实现时使用,也就是说必须有提供支持的接口;且这个接口只能有一个抽象方法
2.必须根据上下文能够判断时才可以使用:

new Thread(new Runnable(){
	@Overwrite
	public void run(){
		System.out.println("这个线程正在执行"+Thread.currentThread().getName());
	}
}).start();

这是普通写法,使用Lambda表达式后:

new Thread((){
	System.out.println("这个线程正在执行"+Thread.currentThread().getName());}).start();

就可以了。
只要是在这种类似的格式下都可以使用
二度省略:参数列表(括号)的数据类型可以省略;如果括号中的数据类型只有一个,那么括号和数据类型都可以省略;大括号和return和分号可以省略(当且仅当方法体只有一行,且要省略就一起省略),这时候的return指的是这个方法的唯一一句话就是return,即光吧return后边的写上去。

【File类】
是对电脑中的文件和文件夹的抽象封装,可以进行一些文件和文件夹相关的操作
file:文件;directory:文件夹/目录;path:路径
pathSeparator:是个字符串,是分隔路径的符号:在Windows里面是";“Linux里面是”:"
这个是用来分隔不同路径的
separator:默认名称分隔符:文件名称分隔符:windows里面是"",Linux里面是"/"
这个是用来分隔一个路径里面的不同的文件的
pathSeparatorChar和separator是字符格式

绝对路径:就是复制过来的路径;相对路径是省略当前路径之后的书写路径,即相对于当前项目位置的路径,
而路径书写不区分大小写
使用字符串表示路径时,反斜杠是转义字符,要用两个来表示一个反斜杠

构造方法:直接写入路径,这个路径可以是存在的也可以是不存在的,最终结尾可以是文件夹也可以是文件,路径可以是绝对路径,也可以是相对路径;直接打印对象的话出来的就是这个路径
写入两个字符串,分别代表父路径和子路径
写入一个file对象和一个字符串,也是与上边相同的效果
常用方法:getAbsolutePath();获取绝对路径,以字符串返回
getPath();获取输入路径,怎么构造的就怎么输出,重写toString就是用的这个
getName();获取最后一个文件或者是文件夹的名称
Length();获取对应的文件的字节数,文件夹和不存在的文件返回0

判断存在的方法:.exists();判断这个对象的路径是否是存在的
.isDirectory();判断这个对象的路径是目录路径与否,若果这个路径本身不存在或是文件路径,则为false
.isFile();判断这个对象的路径是文件路径与否,若果这个路径本身不存在或是目录路径,则为false

关于创建和删除功能的方法:
createNewFile()当且仅当具有该名称的文件不存在的时候创建该文件,路径可以是绝对路径也可以是相对路径,如果路径本身就不存在的话会报错,结尾不是正常文件格式(比如没有加后缀符)的话会使得创建一个无后缀文件。
mkdir():创建File表示的文件夹,只能创建单级文件夹,创建多级的话会返回false
mkdirs();创建多级文件夹,创建成功返回ture,失败返回false
delete();删除当前文件或是文件夹,如果是文件的话则直接彻底删除,文件夹的话要判断里面是否有文件,有的话就删除失败,就算里面有文件夹也是删除失败,必须是空的才行

遍历的方法:就是遍历目录:
list 返回的是String[]
listFiles返回的是File[];这要求File对象的构造方法中传入的路径必须是文件夹,如果不是文件夹的话或者路径不存在的话会抛出NonePointerException;
这两个方法会获取隐藏文件

查找文件的过滤器使用:这个过滤是在由listFiles();方法使用时过滤的,本质上是这个方法的重载:listFiles(FileFilter filefilter);里面放一个过滤器实现类对象,来重写Filefilter里面的方法(其实只有accept一个)。
使用步骤:首先File[] file01=new listFiles(new FileFilter());是将listFiles得到的所有的File对象传递进accept方法中,
(这之前要求创建一个FileFilter接口的实现类)
然后:重写实现类里面的方法accept(),这里的返回值为true的File对象会被保存到File[]数组里面
接着就会根据重写的标准往File[]里面传递符合要求的对象。

FilenameFilter();这个里面的accept里的参数有两个:File dir, String name;这里的dir不同于FileFilter();里的pathname,dir是固定的,是这个文件夹的路径,也就是包含内容的路径;String name才是里面的各个文件或者文件夹的名称。想要判断是否为文件或者文件夹的时候需要进行如下操作:new File(dir,name).isDirectory();进行组合,判断文件名称时候直接使用name即可,无需使用pathname.toLowerCase().endsWith("");判断

这两个定义了实现类的都可以使用lambda表达式简化

【IO流】
输入流/输出流
字符流/字节流
顶层的4个父类:字节输入流:InputStream 字节输出流:OutputStream
字符输入流:Reader 字符输出流:Writer
介绍:字节输出流:FileOutputStream();(字节形式,byte类型输出,主要方法write)
这个的构造方法中传入一个路径,可以是构造好的文件,也可以是没有创建的文件(它会自动创建),然后使用它里面的.write();成员方法向这个文件里面输入数据;
write()里面传入一个0-127之间的整数(write(int num)这个方法里面实际的参数数据类型是int),会根据ASCII码表里面的字符进行对照,如果是先输入一个负数后输入一个数的话,会结合成一个汉字;这个.write();里的参数可以是byte[]数组,也可以是byte[],起始位置,输出的字节数量。

由于上述方法进行output会将文件重新生成并且写入数据,为了能够续写,在进行构造方法时,在路径后面新加一个参数Boolean类型,参数为true时允许续写,为false时不允许续写;所谓续写的话就是指的在这个流关闭运行退出后,再次运行这个流依然按照原来的内容继续往后写。
换行符请使用字符串格式的"\r\n",如果单独写在write("\r\n")里的话,还是要把它转换为byte[]类型;使用.getByte();方法

FileInputStream 这个是从硬盘往内存中读取数据,使用.read();成员方法,将一个文件中的数据读取到操作台上。read();每执行一次指针往后移动一位,最后以及再往后没有数据了会读取-1。(读取的系统的结束符,表示过来是-1)
(输出数据是:write语句->JVM->OS(操作系统)->硬盘,输入数据(Input)时反过来)
(这里给出Arrays类的几个方法的使用:Arrays.toString();方法的参数可以是任何基础类型的数组,得到的结果是String[]数组,内容是这个数组的数据的字符串类型表示形式)
(String类的构造方法中有一个参数是传入byte类型的数组,得到的字符串是对应ASCII码表中的字符的字符串)
一次读取多个数据:read(byte[] bytes)这里面传入的是byte类型的数组,根据这个数组的长度来决定一次要读取几个字节的数据,返回值是读取的有效字节数量(最后3个字节,数组长度为5,则返回3,这个数组的前三个位置被改变了,再次往后读取的话,返回的是-1),byte[]里面是转换过来的0-127数字。如果使用Arrays.toString();得到的是里面的数字的字符串型数组,所以要使用String的构造方法来将它们转换成字符。(由于一次要读取尽可能多的字节,故数组的长度定义为1024*n,但是用普通的构造方法会使得这个数组转换过来之后后面全是空格NULL(如果最后读取的字节数大于文件字节数),故使用String(byte,offset,length),offset是起始位置,length是要转换的长度,就是用0和read的返回值替换即可)(这个length不可为负,注意判断while((readnums=FileInputStream.read(bytes))!=-1))及时退出

对于文件操作时记得先创建两个Input Output类的方法,Input方法是给定从哪个地方接受文件的路径
output方法是给定要写入到哪个地方的路径

字符输出输入流:一次性输入输出字符而不是字节,父类是InputStreamReader,再往上的父类是Reader,writer同样。
输入流:FileReader 构造方法同样传递路径;
接收的时候是一个int类型的整数,所以用int类型的数接受即可,想要看到内容,强制转化成(char)即可
使用数组形式接收的时候,和FileInputStream差不多,只不过是使用char[]数组接收读取过来的数据,其他的就没变,想要打印出来内容也是使用对应的String的构造方法:
new String(chars,0,readernums);直接得到对应的内容数据。
输出流:FileWriter输出的时候这个东西不是直接由控制台就输出到文件里面了,而是要先经过缓冲区buffer,写入的东西在flush();一次之后或者是close();一次之后才会被写入文件,同样的FileWriter();里面的构造方法也是可以加入append 决定是true还是false。
写的时候使用write方法:
(int num)直接对照ASCII码表转换;传入字符数组或者字符串,或者它的一部分(String strs,int offset,int length);
换行符还是:"\r\n"(占两个字节)
总结就是:字节流的write();接受的是单个的int类型或者是byte[]数组,或者是byte[]的一部分;想要往里面传递字符串的时候需要结束.getByte();方法
字符流的write();接收的是单个int,或者是char数组或者是字符串或者是它们的部分。

然后是关于这几个流里面的IOException的处理方法,之前一直是直接抛出,这里进行try catch finally处理:1.fw.close();需要放在finally里面,2.fw的定义要放在try外面,并且要附上初值NULL,3.对于finally中的close()方法本身就有异常,所以再使用try catch进行处理,并且这句话需要判断fw是否为空指针,否则如果路径找不到,没有初值赋给fw,这时候fw是NULL,会并发两个异常。
JDK7和9给了两个新的特性,就是把try后边的括号中加入流定义初始化…但这样做的目的都是为了能够稳定地close这个流,或者控制这几个流变量的生存周期。

Properties 集合,是与流相关的集合,其中的默认KV都是String,使用put(设置map的)方法有个替代:setProperties();KeySet方法替代:stringPropertiesNames(); get()方法(传入K得到V的方法)替代:getProperties();
store()和load()方法分别是把控制台的内容(prop集合)传到文件里,一个是把文件里的东西读取到控制台上。
(InputStreamReader/OutputStreamWriter可以将字节流转换为字符流)
(read()方法的返回值始终是int,单个时(无参)得到的是读取的字节的ASCII,含参时(byte[]char[]得到的是读取的字节(字符)数量))(write()方法)
@@@@@(听说InputStream有mark()和reset()两种方法)

BufferedInput/OutputStream//Writer/Reader
这个是缓冲流,BufferedInputStream用法和FileInputStream几乎相同;
BufferedOutputStream有一点是,他需要使用flush();或者close();方法进行缓存推进,类似FileWriter的方式,
BufferedWriter:别的和FileWriter一样,有特有的成员方法:newLine();是直接往里面输出一个该系统下的换行符
BufferedReader:其它和FileReader一样,只是有特殊的成员方法:readLine()直接读取一行,返回一个字符串,读空行的时候返回一个NULL

OutputStreamWriter:这就是FileWriter的父类,OutputStream的子类,两个构造方法,一个是传进去一个OutputStream对象,另一个是额外传进去一个"UTF-8"之类的文件编码字符串,使用的时候当作FileWrite使用
InputStreamReader:这就是FileReader的父类,InputStream的子类,两个构造方法,一个是传进去一个InputStream对象,另一个是额外传进去一个"UTF-8"之类的文件编码字符串,使用的时候当作FileReader使用;
这两个是用来"修正"FileReader和FileWriter不能读取除UTF-8之外编码的文件的缺点

【序列化和Object流】
有两个继承了InOutput的子类ObjectInputStream和ObjectOutputStream,作用是将一个对象从文件中写入读出;
由于它的底层也是字节流:所以在使用构造法方法的时候要往里面传入一个FileInputStream或者FileOutputStream的对象
特有成员方法:ObjectInputStream的是:readObject();读取一个对象(这个会有一个异常,抛出即可)
ObjectOutputStream的是:writeObject();写入一个对象
这就是对一个对象进行序列化并且放入文件中进行储存,前提是这个类要实现Serializable接口,从而对对象进行序列化,这个接口是个标记接口,没有任何方法;
transient关键字:瞬态关键字(瞬间静态关键字)由于使用static关键字修饰的变量不属于成员变量,从而在序列化时这个变量被忽略,无论此前是什么值,在反序列化输出的时候永远是默认的初始化的值
而这个关键字修饰的时候只起到忽略序列化的作用而没有static的所有成员访问作用;
InvalidClassException异常:是指的反序列化时发现的文件中的对象的序列号和这个类现在的序列号不同时抛出的异常。在这个类继承了Serializable接口之后,每当其被改变的时候都会为这个类生成一个新的序列号,而之前写入文件的序列号和新生成的这个不一样。所以为了避免这异常,需要自己在这个类里面写上一个 (private) static final long serialVersionUID=xxxL;

打印流:平时使用的System.out.println();就是这个流的静态方法,目的是将这个里面的内容打印到控制台上去,创建一个PrintStream ps=new PrintStream();然后使用这个类继承来的那几个方法(writer)比如使用write();方法往上写的时候也是要对照码表的,也就是说还是要写入byte类型的数,但是使用自带的print方法或者println方法可以直接把里面的内容原样打印到文件中。

它的构造方法需要传递一个路径或者一个file类型的对象来确定输出的位置;

System类中有一个静态方法,其参数是一个PrintStream的对象,目的是将System.out.println();输出的内容由控制台改变到这个路径中,方法名称是:System.setOut(PrintStream printstre);
System.setOut();就是指的输出的重定向))))

【网络编程基础】

网络通信协议:UDP:耗资小,通信效率高,发送端和终端不建立逻辑连接;但是数据容易丢失,还会限制传输数据大小。(类似发短信)
TCP:是面向连接的通信协议,在传输数据之前要先在客户端和服务器端做好通信,实现三次握手:
TCP 协议中, 在发送数据的准备阶段, 客户端与服务器之间的三次交互, 以保证连接的可靠:
到第一次握手, 客户端向服务器端发出连接请求, 等待服务器确认。
到第二次握手, 服务器端向客户端回送一个响应, 通知客户端收到了连接请求。
到第三次握手, 客户端再次向服务器端发送确认信息, 确认连接。

端口号是打开一个应用的时候计算机为网络软件随机分配的,使用IP和端口号就可以保证数据稳定发送
常见的端口号:
1.80端口:www.baidu.com:80
2.数据库 的端口号:mysql:3306 orcle:1521
3.Tomcat服务器:8080

客户端和服务器端的通信:
客户端类Client:Socket,此类实现的客户端套接字,套接字是两台机器通信的端点。

服务器类Sever:ServerSocket();创建的服务器的类,其中有方法accept();是用来接收客户端的对象并且用一个Socket类对象来储存的方法,由于服务器类没有IO流相关方法,故必须使用接收到的客户端对象的IO流方法进行信息交换。

重点记忆:本地和端口IO时要使用FileInputStream…客户端和服务器端IO时要用Socket对象的getInputStream…方法
由于(while使用时)read方法第一次不会读取文件结束符(-1)故导致第二次使用(在客户端和服务器端Input时)使得read读不到结束符进入阻塞,所以在第一次从本地读取数据后加上shutdownOutput();方法来给端口的文件加上结束符
为了能多次向服务器上传输数据,将除了ServerSocket sst=new ServerSocket();之后的语句(close除外)放在while(true)里面。
使用线程进行增加效率时:将server的while里的代码放在新的Runnable匿名内部类中,并且使用try-catch处理异常(无法抛出)
使用buffer和线程池效率最高。
【枚举(额外补充)】(enumerate)
被enum修饰的类型就是枚举类型。
枚举默认从0开始的有序数值---->enum Color{RED, GREEN, BLUE}
本质是java.lang.Enum的子类。
方法:
valueOf(String str);传进去的是那个对象的名字,返回的是这个对象(静态方法)
values();返回这个枚举的所有对象(元素)构成的数组(静态方法)
name();返回实例名
ordinal()返回实例声明时的次序,从0开始
getDeclanringClass()返回实例所属的enum类型
equals()
特性:不能继承,不允许使用"="为枚举常量赋值,enum可以通过方法来显示赋值
enum可以添加普通方法,静态方法,抽象方法,构造方法;可以实现接口,不可以继承,实际上是已经继承了Enum类了
工具:EnumSet是同一个枚举使用的高性能Set实现,
EnumMap相比于HashMap等泛用性的Map比起来处理Enum更加高效

补充一个形式:
当你在自定义一个类后(或者是一个系统类),假设他是ClassA,那么有个方法是获得他的父类(以字符串方式返回):ClassA.class.getSuperClass()

enum替换的其实是原来类的class位置

这个类和基本的类没什么两样,其实主要差别在于它的里面的对象都是该类的成员对象
如果这个类叫做EnumTest{
FIRST(“A”);
String word;}
这个第一句就是赋值的基本语句,实质上就等于:
private static final EnumTest FIRST=new(“A”);
而这里少了一个构造方法,应该是含参的构造方法
private EnumTest(String word){this.word=word;}
加上了这个之后就和普通的类差不多了,
这个类在使用的时候不可以new创建实例,只能利用他的static进行直接赋值,(实际上就是把这个静态对象给了另一个对象)
这个类除了长得怪,父类已定而且toString方法重写之后是打印这,定义的是自己的成员,只有static final,不能继承之外,和别的类一样

打印数组的方法:Arrays.toString(这里面放一个数组的数组名即可(自定义类的数组需要重写));打印原理就是调用这个类的toString方法,然后把得到的字符串放到每一个[,]里面。

这里要回想起来那个匿名内部类的知识点是指的这个类继承了抽象类或者是这个类实现了一个接口,此时进行一个多态,将这个接口直接new给一个接口的实现,而后在new后面再加上{},这个里面写上相应的抽象方法的实现,就可以正常使用这个对象了,或者不写对象,直接new,这样的话生成的是匿名对象,使用一次。

【函数式接口】
其实实际上就是只含有一个抽象方法的接口,便于Lambda表达式的使用,
【性能浪费的日志】
改进方法(这里总结一下Lambda表达式的写法:使用处实际上是调用了一个方法,这个方法是一个接口中的方法,然后()->{}格式进行书写,()内是参数,{}内是重写的内容)如果不使用方法的话就是一个匿名内部类的实现。直接new就行
(这是在我使用内部类重写的时候发现的东西,去实现匿名内部类的时候,大括号里的变量还是只能调用main方法里面的变量,成员变量调用不了)
使用匿名内部类(Lambda表达式)时,本质上就是跳过创建实现类,用new 接口名(){}的方式重写调用里面的方法。同时如果本身这个类是继承了接口的,那么在自己的main中创建自己的类的对象时也可以对方法进行重写(前提是这个类已经重写该方法(如enum类))
【常用函数式接口】
1.Supplier:里面的方法是get();是有和传进去的泛型相同类型的返回值的
2.Consumer:里面的方法是accept();是没有返回值的,(

reverseStr("akyuewgvfbha",(name)->{
            String newSt=new StringBuilder(name).reverse().toString();
            System.out.println(newSt);//ahbfvgweuyka
        });

)(这一大步都是在重写内容,name随便取个啥名就行,只是表示要对传进来的字符串执行什么操作)

private static void reverseStr(String str, Consumer<String> cs)
    {
        cs.accept(str);
    }

这个接口还有一个默认方法:andThen();作用是把前后两个接口连起来:
con1.andThen(con2).accept(s);这两个接口都分别重写可以针对这一个字符串进行两种不同的操作;
3.Predicate:里面的抽象方法是:test();返回值是boolean类型
这个接口还有三个默认方法:and(); or(); negate();
前两个是要传递一个相同类型的接口实现(Lambda)作为参数,分别对应&& || !
4.Function<T,P>:里面的抽象方法是:apply();返回值是P类型,传进去的参数是T类型,要求重写过程中完成的是这个变量的类型的转换。(字符串转换包装类:parseInt…,包装类转字符串:String.valueOf();或者直接在这个包装类后边加上+"";他会自动拆箱成为普通类)
这个接口还有一个默认方法:andThen();作用是将同一个数据先经过一次转换后用返回值进行第二次转换。
【Sream流】
使用Stream流不同于循环或者使用迭代器。
Streamstream1=Stream.of(数组名);
Stream是一种管道流,流在调用延迟方法后返回它本身的实现对象,以进行链式编程。当这个流使用一次后被关闭
Stream流是一个类,在collection集合中有个方法叫做.stream();是直接把这个集合变成一个stream流对象,而map不行,map需要使用keySet();valueSet();Map.Entry<T,T>等进行操作来得到一个collection集合,对于数组,由于存在着Stream类中的静态方法of()所以直接使用这个得到即可。(此处还提供另外一个方法:先使用Arrays里的静态方法stream()传递参数为数组名,返回的就是一个stream流对象。)
Stream分为两种方法:延迟方法和终结方法
延迟方法:过滤filter()传递predicate实现类
映射map()传递function实现类
截取limit()传递long(截取前面的几个元素生成新的stream)
跳过skip()传递long(跳过前面的几个元素取后面的所有元素生成新的stream)
concat是静态方法,传递两个stream流,并把它们拼接,返回新的stream流对象
终结方法:count();直接使用,返回值long类型,表示这个stream中有几个元素
forEach();里面传递的是consumer接口的实现类,用作打印这个流里面的元素。

(Stream这个流只要是在停下来之前没有传递给其他流(执行任何操作而不赋值)这个流依然会关闭,再次使用该流会报错)
【方法的引用】Quote(补充知识点:this关键字需要在成员方法中使用,要是想在这个类的main方法中使用这个类的成员方法,需要new一个自己类的对象)
这里有几个常用到的形式:(总之都是为了简化Lambda表达式)
(这类应用一般分为三个阶段:1.先是有一个函数式接口,这个接口中写一个成员方法 2.然后创建一个类,这个类有个方法,至少含有一个函数式接口实现类传递对象 3.最后需要在Lambda表达式重写的时候,他要调用方法,这个方法可以是其他类的成员方法,静态方法,其他类的父类的成员方法,自己类的成员方法,构造方法…核心是将Lambda表达式换成这个直接的方法引用)

【GUI】
一般来说使用一个类继承frame然后直接super(“名字”)即可给这个窗口加上标题。
repaint->update->paint:二次缓存用的时候直接repaint即可,因为paint的话不进行一些操作会不现实点
awt里的point实现画图功能
mouselistener:鼠标监听器
keylistener:键盘监听器

class
mouseadapter:只实现一个就行了(只处理一个)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值