注:自用,无逻辑,复习到哪写到哪
逻辑运算符&&与&区别
&&的特点:如果左边为false则右边式子不再运行(短路效果)
&的特点:不管左边式子的结果如何,右边的式子都要运行
| 和 || 同理
int i = 2;
int j = 2;
if((i++) != 2 & (j++) == 2){}
System.out.println(i); // i=3
System.out.println(j); // j=3
int i = 2;
int j = 2;
if((i++) != 2 && (j++) == 2){}
System.out.println(i); // i=3
System.out.println(j); // j=2
<<、>>、>>>位运算符号
<< 左移 乘2的移动次数
/ >>右移 除2的移动次数
/>>>无符号右移 除2的移动次数(无符号)
System.out.println(2 << 1); // 4
System.out.println(2 >> 1); // 1
String、StringBuffer、StringBuilder区别
用Arrays.toString(int[] a)方法时,源代码里出现了StringBuilder
查询了一下String,StringBuffer,StringBuilder的区别
String:public final class String。
final定义,不可改变的字符串对象。
StringBuffer:public final class StringBuffer extends AbstractStringBuilder
代表一个字符序列可变的字符串对象,一旦通过StringBuffer生成了最终想要的字符串,可以调用toString()转换为一个String对象,实现了线程安全。
StringBuilder:public final class StringBuilder extends AbstractStringBuilder extends AbstractStringBuilder
也代表可变字符串对象,但StringBuilder没有实现线程安全功能,所以性能略高。
String和StringBuffer、StringBuilder转换
String -> StringBuffer/StringBuilder:
StringBuffer类中的构造方法:public String(String str);
StringBuilder类中的构造方法:public StringBuilder(String str);
StringBuffer -> String :
StringBuffer类:public String toString()
StringBuffer和StringBuilder异同
(1)StringBuffer和StringBuilder都继承于AbstractStringBuilder抽象类,
(2)StringBuffer和StringBuilder默认的字符数组元素个数都为16
public StringBuffer(){
super(16);
}
public StringBuilder(){
super(16);
}
(3)StringBuffer实现了线程安全,StringBuilder没有实现线程安全,因此性能较好
//StringBuffer中的源代码
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
//StringBuilder中的源代码
public StringBuilder append(double d) {
super.append(d);
return this;
}
继承关系Super关键字的构造方法
super:代表的是父类的空间标识(代表父类对象的地址值引用)
继承关系中的初始化为分层初始化,需要将父类的数据初始化完毕后,再将子类的数据初始化。
(因为子类实例化对象时可能会用到父类中的成员变量)
class Father{
private String name;
}
class Son{
private int age;
public Son(){
//子类构造默认第一句为super()
super();
}
}
子类继承父类,子类中所有的构造方法都会默认先访问父类的无参构造方法(super())
如果父类没有无参构造,可以在子类的构造方法第一句添加super(参数)调用父类的其他构造方法.
super()有参数时,在子类相同参数构造函数调用时,改变的是父类的成员变量
class Father{
private String name;
public Father(String name){
this.name = name;
}
}
class Son{
private int age;
// //父类没有写无参构造,编译出错
// public Son(){
// //子类构造默认第一句为super()
// }
public Son(){
super("father");
}
}
局部代码块、静态代码块、构造代码块
局部代码块:定义在方法中,限定了代码块中变量的生命周期。
静态代码块:使用static修饰的代码块,随着类的加载而加载,同静态成员属性一样,只加载一次。
构造代码块:定义类中成员位置,用{}括起来的代码块,可以将多个构造方法中的共性代码抽取,放入构造代码块。
运行顺序:静态代码块 - 构造代码块 - 构造方法
如果一个类中存在new语句,则顺序为:静态代码块 - 从上到下new语句或构造代码块 - 构造方法最后执行。
class A{
public A(){
system.out.println("A");
}
{
System.out.println("构造代码块1");
}
C c = new C();
{
System.out.println("构造代码块2");
}
static{
System.out.println("静态代码块");
}
}
class C{
public C(){
System.out.println("C");
}
}
class B extends A{
public static void main(){
B b = new B();
}
}
//执行结果:
//静态代码块
//构造代码块1
//C
//构造代码块2
//A
多态
java三大特征之一(封装、继承、多态)
多态:一个事物在不同时刻体现的不同形态
多态的前提条件:
1)必须要有继承关系
2)必须要有方法重写
3)必须有一个父类引用指向一个子类的对象(向上转型)
多态的成员访问特点:
(左为父类,右为子类)
1)成员变量:编译看左,运行看左
2)成员方法:编译看左,运行看右
3)构造方法:对当前对象中的数据进行初始化
class Father{
public int num = 10;
public void fun(){
System.out.println("Father");
}
}
class Son{
public int num = 20;
public void fun(){
System.out.println("Son");
}
public void fun2(){
System.out.println("Son独有");
}
}
class Test{
public void main(String args[]){
Father fa = new Son();
System.out.println(fa.num);
fa.fun();
}
}
//执行结果
//fa.num = 10;
//fa.fun(); = Son;
多态的弊端:
不能访问子类的独有的方法
解决办法:向下转型 ,即将父类引用再次转型为子类,前提是必须要先有向上转型。
class Test{
public static void main(String args[]){
Father fa = new Son();
Son so = (Son)fa;
so.fun2();
}
}
//运行结果
//Son独有
内部类
内部类定义:内部类是指定义在类中的一个独立且完善的类结构
缺陷:破坏了程序的结构
优势:能够轻松的访问外部类的私有属性
//如果不使用内部类,通过内部类访问外部类的私有属性
class Outer{
private String msg = "外部类私有属性";
public String getMsg(){ //要想访问私有属性必须通过getter方法
return this.msg;
}
public void fun(){
Inner in = new Inner(this); //实例化内部类对象
in.print();//调用方法
}
}
class Inner{
private Outer out = null;//要想调用Outer的get方法必须要有实例化对象
public Inner(Outer out){ //通过构造函数获取一个Outer对象
this.out = out;
}
public void print(){
System.out.println("msg = " + this.out.getMsg()); //获取外部类的私有属性
}
}
class Test{
public static void main(String args[]){
Outer out = new Outer();
out.fun();
}
}
如果定义成内部类,则内外部类访问对方的私有属性不再通过getter方法
class Outer{
private String msg = "外部类私有属性";
public void fun() {
Inner in = new Inner();
in.print();
System.out.println(in.info);
}
//可以用Private修饰
class Inner{
private String info = "内部类的私有属性";
public void print() {
System.out.println(msg);
}
}
public class InnerClass {
public static void main(String[] args) {
Outer out = new Outer();
out.fun();
}
}
具有内部类的类,在编译后会自动形成一个Outer(美元符号)Inner.class的类文件,其中$符号在java里等同于.
因此当内部类没有被private修饰,可以直接在外部实例化内部类的对象。
public class InnerClass {
public static void main(String[] args) {
Outer.Inner in = new Outer().new Inner();、
in.print();
}
}
static修饰内部类 ,则内部类相当于外部类,内部类的属性和方法不能用static修饰
class Outer{
private static final String MSG = "外部类私有属性";
static class Inner{
public void print() {
System.out.println(Outer.MSG);
}
}
}
public class StaticInner {
//要想实例化inner类对象,只需要根据外部类.内部类的结构实例化对象即可
public static void main(String[] args) {
//外部类.内部类 内部类对象 = new 外部类.内部类()
//对比: Outer.Inner in = new Outer().new Inner();
Outer.Inner in = new Outer.Inner();
in.print();
}
}
总结:内部类最大的优势是可以访问外部类的私有属性,一般运用在一些内部结构不需要被外部操作,只需要被外部类操作的情况,例如链表。
Lambda表达式
jdk8引入了Lambda表达式,本质是实现了函数式编程,使得代码更加简洁。要想实现Lambda表达式,必须满足SAM(Single Abstract Method),即只有一个抽象方法。
只有一个抽象方法的接口称为函数式接口,能被Lambda所使用的。
注解:@FunctionalInterface
- Lambda表达式:
- 1 方法没有参数:()->{};
- 2 方法有参数:(参数,参数)->{};
- 3 如果现在只有一行语句返回:(参数,参数)->语句;
@FunctionalInterface
interface IMessage{
public void send(); //方法没有参数
}
@FunctionalInterface
interface IMessage2{
public void send(String msg); //方法有参数
}
@FunctionalInterface
interface IMath{
public int sum(int a,int b);//方法有返回值
}
class JavaDemo{
public static void main(String args[]){
IMessage msg = ()->{
System.out.println("无参数方法");
};
msg.send(); //结果:无参数方法
IMessage2 msg2 = (str)->{
System.out.println(str);
};
msg2.send("有参数方法"); //结果:有参数方法
IMath math = (a,b)->{
return a + b;
};
System.out.println(math.sum(10,5));//结果:15
}
}
函数式接口同样可以添加static和default方法,都是jkd8的新特性,为函数式接口服务
@FunctionalInterface
interface IMessage{
public void send(String str);
public default void print() {}
}
Runnalbe接口也是函数式接口,因此可以使用Lambda表达式
Runnable run = ()->{
System.out.println("runnable");
} ;
Thread myThread = new Thread(run);
myThread.start();
系统提供的函数式接口在java.util.function的开发包,里面有可以直接使用的函数式接口
(1)功能性函数式接口
@FunctionalInterface
public interface Function<T,R>{
public R apply(T t);
}
(2)消费型函数式接口。只能够进行数据的处理操作,而没有任何返回
@FunctionalInterface
public interface Consumer{
public void accept(T t);
}
(3)供给型函数式接口
@FunctionalInterface
public interface Supplier{
public T get();
}
(4)断言型函数式接口。进行判断处理
@FunctionalInterface{
public interface Predicate{
public boolean test(T t);
}
public class FunctionDemo {
public static void main(String[] args) {
Function<String,Boolean> fun = "**Hello" :: startsWith;
System.out.println(fun.apply("**")); //true
Consumer<String> fun1 = System.out :: println;
fun1.accept("接收"); //接收
Supplier<String> fun2 = "ABCD" :: toLowerCase;
System.out.println(fun2.get()); //abcd
Predicate<String> fun3 = "abcd" :: equalsIgnoreCase;
System.out.println(fun3.test("abcd")); //true
}
}