java %08d_Java基础

写了一段时间java,回顾下基础知识

C1

在命令行运行Java

javac filename.java

java filename

基本数据类型

基本类型是Java语言里的一种内置的特殊数据类型,并不是某个类的对象。 直接使用,如

char a = 'x';

这里x就是字面值

四种整型

byte 8位 2^8 -128~127

short 16 位

int 32位

long 64位 整型字面值以l结尾就是long,否则是int

默认是十进制,十六进制对应0x 二进制对应0b 八进制对于00

两种浮点型

float 32位

double 64位

浮点型字面值默认是double,后加f就是float。

以上六种默认值皆为0或0.0,均为带符号数。

一种字符型

char 只能保存一个字符,用单引号引起,长度为16位

char a='c';++aa is b;

一种字符串型

String str="xxx";

严格来说,字符串是Immutable的

类型转换

强制类型转换用于从大到小

不同类型数据进行运算取较大数的

如果任何运算单元的长度都不超过int,那么运算结果就按照int来计算 (如两个byte相加,结果一定是int)

命名规则

变量命名只能使用字母 数字 $ _ (中文也可以但我不会这么干的)

final

当一个变量被final修饰的时候,该变量只有一次赋值的机会

操作符

逻辑操作符

注意java中逻辑操作符的操作数是true和false 不会是别的

短& 长&& 短| 长|| 非!

位操作符

有~ & | ^

三元操作符

? :

用于获得输入

Scanner s= new Scanner;

s.nextint();s.nextline();s.nextfloat();

因为回车也算是字符串的一部分,刚好也是字符串(line)结束的标志,故在回撤之后读取字符串需要额外加一行s.nextline();

流程控制

基本的三种循环

switch,在java中,可以是四种整型,String,char和enum,语法如下

switch(x){

case xx:

;

break;

case xx:

;

;

break;

}

数组

在java中,数组是固定长度的,包含了相同类型数据的==容器==

声明

声明 int a[]

引用 new int[5]

赋值 声明引用后可赋值,也可以 int a[]=new int[5]{1,2,3,4,5}orint a[]=new int[]{1,2,3}orint a []={1,2,3}

增强型for 循环

for (int each:a) xxx;

工具类Arrays

Arrays.sort

Arrays.toString

Arrays.binarySearch

Arrays.equals

Arrays.fill

其他待补充

类与对象

创建与引用

new Class();是创建

Class c1= new Class();//左边是引用

Class c2

c2=c1;//更改引用

变量的修饰符四种

先搞清类之间的关系,同包关系,子类关系,笛卡尔乘,得到

同包子类

同包非子类

不同包子类

没关系,不同包非子类

之后,四种修饰符及用处如下

private 只有自己能访问

缺省 同一个包里的可以访问或者继承,否则不行

protect 同一个包里的或者是子类,则可以继承

public 谁都可以

初始化

对象属性初始化有3种

声明该属性的时候初始化

构造方法中初始化

初始化块

类属性初始化有2种

声明该属性的时候初始化

静态初始化块

static{

itemCapacity = 6;//静态初始化块 初始化

}

singleton 单例模式

构造方法私有化

静态属性指向实例

public static的 getInstance方法,返回第二步的静态属性

饿汉模式、懒汉模式还有许多其他模式 待补充

枚举类型 enum

public enum Season{

Spring,Summer,Fall,Winter

}

for(Season s:Season.values())

System.out.println(s);

接口与抽象

instance of 判断对象是否是子类

多态的实现 需要向上类型转换和override 而隐藏就是静态方法(类方法)的重写(覆盖)

构造方法 子类一定会调用父类的构造方法,如果父类没有构造方法(确切的说,任何一个类没有显示声明构造方法),那么编译器自动加上无参无内容的空父类构造方法,如果父类生命了无参构造方法,那么子类直接调用,如果父类只声明了有参构造方法,那么子类

A:在父类中加一个无参构造方法 B:通过使用super关键字去显示的调用父类的带参构造方法==(需要放在子类的构造函数的第一句)==C:子类通过this去调用本类的其他构造方法

==所有对象==都继承自Object对象,因此也继承了其一些方法如 String toString(),boolean equals(),wait(),notify(),notifyall(),hashcode()等方法。

抽象类 一旦一个类中有抽象方法(public abstract void xx();)这个类就称为抽象类,必须加上abstract,也因此,抽象类中不一定必须全是抽象方法,也可以有实体方法,叫做==默认方法==,interface中也是这样。但是interface中的方法一定是默认为public static final,while抽象类中这三个属性都是可选的(抽象方法和实体方法都如此)

默认方法可以写在接口和抽象类中,通过default声明(否则在接口中会报错)

数字与字符串

装箱与拆箱 继承自抽象类Number的所有类都对应一个基本类型(六种数字)

转换到字符串 基本类型,使用String.valueof(i); 装箱类型,直接使用继承自Object的to String();

转换到其他类型 调用其他类型的封装类的静态方法xx.parsexx(String str);

数学方法 round(); MATH.PI;MATH.E,sqrt();

Character 对应char的类 有isdigit 和isnumber方法用于判断是否位数字或是否为字符串(联想 也可以通过=判断,还可通过正则简化枚举)

格式化输出。

//总长度是8,左对齐

System.out.format("%-8d%n",year);

//总长度是8,不够补0

System.out.format("%08d%n",year);

//千位分隔符

System.out.format("%,8d%n",year*10000);

本质上是printf(1)在DOS和Windows中,每行结尾是 “\r\n”;(2)Linux系统里,每行结尾只有 “\n”;(3)Mac系统里,每行结尾是只有 "\r"。

字符串处理函数

charAt 获取给定字符的位置

toCharArray 转换成字符数组

subString 截取子串

split 分隔开

trim 去掉空格

toLowerCase toUpperCase 转换成大小写

indexOf lastIndexOf contains 字符串的位置,是否包含

replaceAll replaceFirst 字符串替换

字符串比较

== 判断是否为同一个对象

equals(String str)判断是否一样

startsWith以...开始 endsWith以...结束

Stringbuffer 变长字符串

append delete insert reverse 以及length capacity 这些属性 性能较高

日期处理

Date d=new Date();可选参数 int 表示从1970年1月1日过了x毫秒(10^-3秒)对应的时间。

gettime返回long类型,表示从那时到现在经历了多少毫秒

System.currentTimeMillis(); 返回系统当前时间,long型。 日历类型:

//通过日历对象得到日期对象

Date d = c.getTime();

Date d2 = new Date(0);

c.setTime(d2); //把这个日历,调成日期 : 1970.1.1 08:00:00

还有add和set方法。

通过这种方式来进行格式化输出

M 代表月

d 代表日

H 代表24进制的小时

h 代表12进制的小时

m 代表分钟

s 代表秒

S 代表毫秒

SimpleDateFormat sdf=new SimpleDateFormat("y-M-dd");

System.out.println(sdf.format(new Date(System.currentTimeMillis())));

C2

异常处理

通过try catch finally的方式进行处理。

异常可分为错误ERROR和Exception,后者又分为运行时异常(runtimeException)和可查异常,三者都继承了Throwable类

[图片上传失败...(image-5b2c1d-1551662952330)]

文件操作

File f = new File("");

// 以字符串数组的形式,返回当前文件夹下的所有文件(不包含子文件及子文件夹)

f.list();

// 以文件数组的形式,返回当前文件夹下的所有文件(不包含子文件及子文件夹)

File[]fs= f.listFiles();

// 以字符串形式返回获取所在文件夹

f.getParent();

// 以文件形式返回获取所在文件夹

f.getParentFile();

// 创建文件夹,如果父文件夹skin不存在,创建就无效

f.mkdir();

// 创建文件夹,如果父文件夹skin不存在,就会创建父文件夹

f.mkdirs();

// 创建一个空文件,如果父文件夹skin不存在,就会抛出异常

f.createNewFile();

// 所以创建一个空文件之前,通常都会创建父目录

f.getParentFile().mkdirs();

// 列出所有的盘符c: d: e: 等等

f.listRoots();

// 刪除文件

f.delete();

// JVM结束的时候,刪除文件,常用于临时文件的删除

f.deleteOnExit();

File f = new File("d:/LOLFolder/LOL.exe");

System.out.println("当前文件是:" +f);

//文件是否存在

System.out.println("判断是否存在:"+f.exists());

//是否是文件夹

System.out.println("判断是否是文件夹:"+f.isDirectory());

//是否是文件(非文件夹)

System.out.println("判断是否是文件:"+f.isFile());

//文件长度

System.out.println("获取文件的长度:"+f.length());

//文件最后修改时间

long time = f.lastModified();

Date d = new Date(time);

System.out.println("获取文件的最后修改时间:"+d);

//设置文件修改时间为1970.1.1 08:00:00

f.setLastModified(0);

//文件重命名

File f2 =new File("d:/LOLFolder/DOTA.exe");

f.renameTo(f2);

System.out.println("把LOL.exe改名成了DOTA.exe");

System.out.println("f1的绝对路径:" + f1.getAbsolutePath());

// 相对路径,相对于工作目录,如果在eclipse中,就是项目目录

File f2 = new File("LOL.exe");

System.out.println("f2的绝对路径:" + f2.getAbsolutePath());

// 把f1作为父目录创建文件对象

File f3 = new File(f1, "LOL.exe");

流是传输数据的一个方式,从程序的角度来区分输入流和输出流,来源可以是硬盘、程序、网络等任意地方

FileInputStream fis= new FileInputStream(new File(str));

InputStream和OutputStream是最基本的字节流,文件输入输出流继承了他们。

关闭流有三种不同的编写位置,可以在try中关闭,但可能因为在fis.close执行前就抛出异常导致无法关闭,也可以把close定义在finally中,但声明xx=null就要在catch前,因为try语句块和finally语句块不共享变量,最后一种方法是sdk7开始的try后的()声明和初始化流,这样在try结束的时候就自动关闭了==待补充==

Reader Writer和刚才的InputStream OutputStream是一个地位的,不过不是字节而是字符读取。

集合框架

用处:变长数组,可以同时存放多种类型,如各种类和基本类型。ArrayList ar=new Arraylist();,然后调用add();remove();get();set();等方法即可对其操作,它会自动变长度。

还可以指定其可以增加的类型,如ArrayList lh=new ArrayList <>();(后边一个<>中指定的类型在SDK7后可以省略。这样,就保证只能add这种类型。此外,通过实现统一个接口,可以实现只能增加确定数目个类。

ArrayList实际上是实现了List接口==待补充==,继承了其所有方法。

ArrayList的遍历,可以通过for(;;)get(index)来取得;也可以通过 Iterator it =lh.iterator();这样来获得迭代器,然后通过it.hasnext()和it.next()进行遍历,还可以通过foreach循环进行遍历。只是在要删除其中某些元素时,直接使用it或者foreach会出现错误==待补充==(为什么?),,可以放到一个临时容器,删除临时容器来实现对象(内存空间的释放),这样在原List(可以发现其为链表结构)中依然是连续的。

LinkedList相比ArrayList实现了队列、双向链表的接口,因此多了addlast();addfirst();以及offer() 在最后添加元素;poll() 取出第一个元素;peek() 查看第一个元素这些方法

二叉树排序、遍历算法java实现时应注意的事情,如travel方法应独立于对象==待补充==

HashMap和HashSet,后者封装了前者,都是无序的

Collection是一个接口,List,Deque(间接继承),Set都继承了它,但Map是存放的,故无关。Collections是一个类,容器的工具类,就如同Arrays是数组的工具类

HashMap和Hashtable都实现了Map接口,都是键值对保存数据的方式区别1: HashMap可以存放null;Hashtable不能存放null区别2:HashMap不是线程安全的类;Hashtable是线程安全的类

HashSet: 无序;LinkedHashSet: 按照插入顺序;TreeSet: 从小到大排序

泛型generic

之前用过的,集合中的泛型 ArrayList lh=new ArrayList <>()集合中实现了某个接口使得可以直接<>这样写。相对的:public class Mystack{}``Mystack mh=new Mystack<>(); 自己声明即可,其中T将会替换掉类中方法返回值、参数类型和属性的类型声明(可以)。

如果希望只取出,不插入,就使用? extends Hero;如果希望只插入,不取出,就使用? super Hero;如果希望,又能插入,又能取出,就不要用通配符?

子类泛型和父类泛型都不能相互转换,原因是子类转父类(若是对象则可以)再加新的,内存格式不对(其他子类),父类转子类,倒是可以加进去,但是取出会有问题。根本原因是相比对象,集合泛型同时具备了加入和取出操作,是双向的,而向上类型转换是单向的,导致转换无法进行。

Lambda表达式

大体来说,有三种类型来写一段代码实现一个功能,一是直接刚代码,但耦合性大,不易修改,不好复用,二是通过类解耦出来,通过匿名类new一个接口Comparator c = new Comparator() {}(集合的排序方法,使用的泛型,一般可以没有)在其中重载接口中的方法,并在另一个方法中和它要处理的数据一起作为参数传入方法,但这样会生成很多匿名类。三是直接把数据和方法传入,那个方法就是Lambda表达式,格式是(argu)->(expression).使用Lambda表达式的好处是简洁,坏处是长了不易读,不易维护,不易输出日志。

多线程

多线程是指一个进程中多个同时进行的任务==待补充==,java中多线程实现方式由继承thread类:class A extends Thread;A aa=new A();A.start()(需要在A中重写run()方法);实现runnable接口class B implements Runnable;B bb=new B;new Thread(B).start(),Runnable中声明了run()方法,自然B中需要重载,但因为R中没有start方法,只有Thread中有start()方法,故需要通过Thread的构造函数来进行启动线程。匿名类也可以实现多线程。Thread t1=new Thread(){run(){};};t1.start();匿名类的一个好处是可以很方便的访问外部的局部变量。前提是外部的局部变量需要被声明为final。(JDK7以后就不需要了)。还能使得代码简洁。

线程的实现作为一个类或者接口肯定有一些方法,包括yield暂停,sleep()睡眠,setpriority设置优先级,setDaemon(true);设置为守护线程

除了这些方法,多个线程对一个资源进行操作就会出现问题,根本原因是一个Thread中操作非原子,可再分,因而处理器执行A的一部分再去执行B,就会造成数据出错(脏数据?)。的最简单的:银行存款问题。

那么,如何解决?根据刚才说的,只需要一个线程占有资源的时候,其他资源不能同时访问进而占有进程即可。可以通过java关键字sy来实现synchronized

Object someObject =new Object();

synchronized (someObject){

//此处的代码只有占有了someObject后才可以执行

}

这里someobject就相当于一个信号量,也就是说,synchronized保证同时只有一个线程占有代码块中的操作。 因此,也可以用继承了THread类的类作为Sy方法的参数,this(在方法声明)或者对象名(在代码块中)都可以。 进一步地,直接在类的定义的方法前加上sy,表示这个方法在被调用时所属对象被锁定(和上文的sy(this)是一样的。

与syn类似的lock()

Lock lock = new ReentrantLock();这个lock也可以完成syn所能完成的任务,只是syn在代码块结束后自动释放,而lock必须手动释放,因此若忘记释放,就会造成死锁;另一个区别是lock可以试图在一定时间内占用,如果占用失败,就拉到,这可以很大程度上减少死锁的产生。

相对应syn的交互办法,lock也有相应的交互办法,分别是await、signal、signalall,这些方法从lock对象得到的condition那里得到。

此外,syn是java中的关键字,而lock是一个接口,是代码层面的实现。

线程安全的类

如果一个类,其方法都是有synchronized修饰的,那么该类就叫做线程安全的类。同一时间,只有一个线程能够进入 这种类的一个实例 的去修改数据,进而保证了这个实例中的数据的安全(不会同时被多线程修改而变成脏数据)。java本身实现了一些线程安全的类。==待补充==

死锁

死锁是在线程安全的基础上产生的,如t1占有r1,之后想要占有r2,whilet2占有r2,之后想要占有r1,此时它俩互相等待,进入死锁。扩展到更多的线程和资源的关系中,判定方法见操作系统(总算操作系统没白学)==待补充==

如何解决死锁?==待补充==

线程交互

多个线程同时进行,肯定需要交互,可以通过网络监听+switch。也有一些方法如wait()和notify(),属于Object上的方法,前者使当前线程停下等待后者,后者使得因前者停下的线程继续运行。

生产者消费者问题

一开始我自己写的时候,是在生产者和消费者这两个类中实现了notify()和wait(),然后在wait那里报错,一开始写的还是this.wait().....后来改成了ms.wait(),报错是java.lang.IllegalMonitorStateExceptiongoogle得知,是因为调用.wait()的方法没有+同步锁, 即syn,因此,wait()需要放在资源(的方法)中,而非调用资源的线程中!根本原因是this.wait()表示 让占有this的线程等待,并临时释放占有。this.notify() 表示通知那些等待在this的线程,可以苏醒过来了。 等待在this的线程,恰恰就是减血线程。 一旦recover()结束, 加血线程释放了this,减血线程,就可以重新占有this,并执行后面的减血工作。

线程池

类似刚才的生产者消费者问题,线程池的资源是指一个个需要解决的问题,而消费者是线程池中的线程,生产者是....emmm添加任务的人。

`ThreadPoolExecutor threadPool= new ThreadPoolExecutor(10, 15, 60, TimeUnit.SECONDS, new LinkedBlockingQueue());

`然后 通过excute(Runnable x)来添加任务。

atomic operation

详见os,不可再分的操作,java中提供了 AtomicInteger at= new AtomicInteger(3);来保证++i的原子性操作(本来只有这种int i=1;是原子操作的)。

网络编程部分

小的聊天工具

Client.java&Server.java聊天,傻到每个.java建立一个监听和一个发送,这样一个开启监听的时候也开启也发送,这个发送永远了到不了另一个监听,因为另一个监听还没开(试想你原来的Client先开的话,Server是接受不到消息的)。所以,只需要一个Socket连接。然后把接收和发送消息写到同一个while(true)里,此时idea会报错:循环不会结束,后边的访问不到,这时业务逻辑稍微改一下不===true就好。但是while()这样有一个问题,就是必须是一问一答的形式,因为一定会是{接收消息;发送消息;}的样子。此时需要多线程(两个就够了)。

网络基础知识部分

java可以监听一个ip的一个端口来接收消息,至于具体怎样,去看计算机网络吧==待补充==

C3

反射Reflection

类对象,就是用于描述这种类,都有什么属性,什么方法的。对比Hero对象,Animal对象。

获取类对象有三个方法,分别是类名.class;对象名.getclass;以及Class.forname(类名);

之后通过类对象的构造器和强制类型转换获得想要的对象

Constructor c=b.getConstructor();

Hero hh=(Hero)c.newInstance();

除了第一个,其他都会初始化要求类对象的类的类方法即static语句块。

与反射有关的,syn锁+在对象方法上,占用的对象是当前对象,也即当前对象无法被其他对象访问,而+在类方法之前,占用的对象就是类对象。

通过反射获取对象其内容是空的,要通过获取到的唯一的类对象的方法进行设定,具体如下

Field f1=hh.getClass().getField("name");

Field f2=hh.getClass().getDeclaredField("hp");

f1.set(hh,"temmo");

区别是前者可以获得public的属性,包括从父类继承的,后者可以获得所有属性,但不能获得继承来的,同时,private的不可直接访问(protected的在同一个包里可以(本来就可以)),需要方法setAccessible(true);

获取对象之后就需要获取、调用方法,与刚才类似

Method m=hh.getClass().getDeclaredMethod("setHp", double.class);

m.invoke(hh,23.9);

那么,这样做又什么好处呢?从上边看出来,反射可以通过String类名直接获得类对象,进而获得对象并对其属性和方法进行修改。也就是说,可以通过外部配置文件决定生成的类。(如果要用java自己实现,读取文件之后做if或者switch,或者把那个String型类名嵌入到java代码中)这样就实现了解耦。Spring框架就是这么干的。

Annotation

java中注解是可以被编译器接收的对代码段起影响的代码,工程上目的主要是解耦。可以分为内置注解、框架注解和自定义注解,其中自定义注解需要元注解进行配置,内置注解也需要,都需要(......)。根据注解的作用域@Retention,注解分为RetentionPolicy.SOURCE: Java源文件上的注解;RetentionPolicy.CLASS: Class类文件上的注解;RetentionPolicy.RUNTIME: 运行时的注解。

还有自定义注解,通过配置一个@interface,并在另一个类前用其注解,然后通过反射这个类获得在注解处配置的值,还是有点迷,这样做的意义除了解耦还有啥?==待补充==

日志

通常,调试信息需要通过打印来输出,但这样有一些缺点。通过日志更加方便,在使用之前,首先要导入jar包,idea导入jar包的方式。

待续 ......

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值