1a Java基础.txt
UP 返回
1.cmd命令
cd .. 返回上级目录
cd \ 直接返回当前根目录
dir 显示所有文件
cls 清屏
2.java9新特性
2.1 cmd中可以直接通过jshell命令进入脚本
后面可以直接输入java语句一句一句执行,省去了输入main和编译的步骤,例如
System.out.println("aaaaaaaaaa"); 再按回车即可直接输出
int a=10; 回车
int b=20; 回车
int result=a+b; 回车
以上均可直接输出结果。
适用于轻量级的java小程序
2.2 对于byte/short/char,如果右侧赋值的数值没有超过范围,那么java编译器会自动隐含地补上对应的强转(byte)(short)(char)。如果超过了,直接编译报错
在给变量进行赋值时,如果右侧的表达式中全部是常量,没有任何变量,那么编译器javac会直接将若干个常量表达式计算得到结果:short result=5+8,编译后的.class中相当于就是short result=13。
如果单纯的用 short a=5;short b=8;short result=a+b; 是会报错的,因为左侧需要是int类型
3.对象和内存的关系
运行main之前,方法区(Method Area)需要最先有数据,保存的是.class相关数据(成员变量和成员方法)
最先从main开始运行,运行则进栈(Stack)
创建的对象,名称在栈中,其保存的是一个地址,该地址指向堆(Heap),堆中保存着具体的对象数据,包括成员变量和方法,但堆中的方法保存的也是一个地址,指向方法区的实际方法。
栈中进行赋值操作时,改变的是堆中的数据值
需要调用方法时,对应的方法的语句被调入栈执行(同上面的main),位于栈的最上方。全部执行完毕以后出栈
新new出来的对象在堆中会有另外一个区域存放对应的数据(独立的成员变量,独立的成员方法,但方法是和上面的对象指向同一个方法区位置的):Phone one=new Phone(); Phone two=new Phone();
通过对象给新对象赋值时,新的对象将直接指向栈中的旧对象地址(引用):Phone one=new Phone(); Phone two=one;
类的局部变量位于栈内存,成员变量位于堆内存。局部变量随着方法进栈诞生,随着方法出栈消失;成员变量随着对象创建而诞生,随着对象被垃圾回收而消失
局部变量和类的成员变量重名时,根据就近原则优先使用局部变量,可以通过this来访问成员变量。this关键字一定在方法中,那么这个方法被谁调用,那么this指的就是调用他的人
4.自1.5开始,支持自动装箱和拆箱(基础类型和包装类型的自动转换)
5.static关键字
使用static关键字修饰的,这样的类容不属于每一个对象,而是属于类,所有对象共享同一份。
静态方法可以直接通过对象名来调用,也可以通过类名来调用。前者写法在编译以后仍然会被javac翻译为 类名称.静态方法名
静态不能直接访问非静态,因为在内存中是先有静态内容,后有非静态内容。静态方法中不能有this,因为this代表当前对象,但静态同对象无关
方法区中有一块独立的空间 静态区,专门用来存储静态的数据(可以认为方法区.class中关于静态的成员是通过地址映射到静态区)。在栈中要是用静态变量时,直接到类中去寻找,即静态区寻找,同对象没有任何关系,故堆中也就没有静态的成员属性存在
静态代码块:
public class 类名{
static{
//静态代码块内容
}
}
当第一次用到本类时,静态代码块执行唯一的一次。静态内容总是优先于非静态,所以静态代码块比构造方法先执行。一旦执行以后,静态代码块将不再执行,故一般用来一次性地对静态成员变量进行赋值(JDBC相关操作会用到)
6.继承
6.1 父类和子类拥有同样的成员变量时的访问规则:
1)直接通过子类对象访问成员变量的话(Zi zi=new Zi();System.out.println(zi.num);//Zi类继承于Fu类,两者都有一个变量num,且值不同),等号左边是谁(zi),就优先用谁(用zi里的num),没有则向上找
2)间接通过成员方法来访问成员变量时,该方法属于谁,就优先用谁,没有则向上找(比如Fu类中的方法methodFu()是用来输出num,此时若调用zi.methodFu(),该方法虽然继承了,但是属于父类的,故最后输出的仍然是Fu中的num)
public class Zi extends Fu{
int num=20;
public void method(){
int num=30;
System.out.println(num);//30,局部变量
System.out.println(this.num);//20,访问到本类的成员变量
System.out.println(super.num);//10,访问父类的成员变量。方法的访问规则相同
}
}
6.2 子类构造方法中有一个默认隐含的 super() 调用,所以一定是先调用父类的构造方法,后执行子类的构造方法(默认的super是无参构造)
可以通过super关键字在子类构造中调用父类重载的构造函数
super调用语句必须是子类构造方法的第一个语句
6.3 super可以访问父类的变量、方法和构造函数,this可以访问本类的变量、方法(一个方法中访问另一个方法) 和本类的构造方法(此时this(...)语句也必须是第一个语句,且只可用一个。this和super两种构造调用,不能同时使用)
public Zi(){
this(123);//访问本类的另一个构造方法
}
public Zi(int n){
this(1,2);//该构造方法也可以调用别的构造
}
public Zi(int n,int m){
//但是构造方法不能互相循环调用,编译器会报错
}
6.4 在方法区中,子类中的super会存储一个地址指向父类。创建子类对象时,在堆中,子类的数据中会包裹一个父类的数据,this关键字相当于指向子类内容中,super关键字相当于指向父类内容中
7.重写(覆盖,覆写)
重写必须满足:子类方法的返回值必须小于等于父类方法返回值的范围;子类方法的权限必须大于等于父类方法的权限修饰符( public>protected>(default)>private )
8.接口
8.1 interface编译后生成的字节码文件仍然是.class文件
8.2 接口中可以包含的成员:(详见8.4)
java7中:1.常量 2.抽象方法
java8中:除了以上,还可以有: 3.默认方法 4.静态方法
java9中:除了以上,还可以有: 5.私有方法
8.3 接口中的抽象方法可以省略任意关键字:
public abstract void method1();
abstract void method1();
public void method1();
void method1();
以上这些写法都可以表示抽象方法
8.4 从java8开始,接口里允许定义默认方法,用来解决接口升级的问题。因为接口如果升级,需要添加新的抽象方法时,那么之前所有的实现类都将因为未实现该方法而受到牵连
默认方法的格式为:
public default 返回类型 方法名(参数列表){ //default不可省略
//方法体
}
默认方法会被实现类继承过去,实现类对象可以直接调用该方法,实现类也可以覆盖重写该方法(调用规则与父类子类的调用规则相同)
从java8开始,接口里允许定义静态方法,格式为:
public static 返回类型 方法名(参数列表){ //static不可省略
//方法体
}
即直接将abstract或者default换成static即可。使用时也是直接通过 接口.方法 来调用(同静态方法一样。因为实现类可以实现多个接口,故不可通过实现类对象来调用静态方法,不然会有冲突,其实本质仍然是因为静态和对象没有任何关系,只与类有关)
从java9开始,接口里允许定义私有方法
我们需要抽取一个共有的方法,用来解决两个默认方法之间重复代码的问题。但是这个共有方法不应该让实现类来使用,所以应该是私有化的
1)普通私有方法:private修饰即可,用来解决多个默认方法之间的重复代码
2)静态私有方法:private static修饰,用来解决多个静态方法之间重复的代码
接口中可以定义成员变量,但是必须用public static final 来修饰(可省略,但效果不变,对应修饰词是隐含存在的),且必须手动赋值,一般用 NUM_OF_TEST 这种格式来命名,从效果上看,这其实就是接口的常量。通过 接口.成员变量名 来访问
8.5 接口间的继承是可以多继承的
public interface MyInterface extends Interface1,Interface2{
}
多个父接口中的抽象方法如果同名,继承不会影响,但子接口只会有一个同名的方法(可以通过实现类验证)
多个父接口中的默认方法如果同名,那么子接口必须对默认方法进行覆盖重写,而且要用default修饰
9 多态
9.1 多态针对的是对象,在代码中的体现为:
父类 对象名=new 子类();
接口 对象名=new 实现类();
9.2 在多态的代码中,成员变量的访问规则同6.1,成员方法的访问规则为:看new的是谁,就优先用谁,没有则向上找。
成员变量:编译看左边,运行还看左边(类比6.1)
成员方法:编译看左边,运行看右边(见下方举例)
Fu obj=new Zi();
obj.method();
obj.methodFu();
obj.methodZi();//虽然运行的时候是看子类的方法,但编译是看左边,methodZi并不是父类有的方法,所以这种写法在编译时即会报错(编译器报红)
9.3 对象的向上转型,其实就是多态的写法:父类 对象=new 子类();
对象的向下转型,是一个还原的动作。
Animal animal=new Cat();//向上转型
Cat cat=(Cat)animal;//向下转型,还原回Cat。向下转型以后,animal就可以访问Cat自有的方法了(参9.2,本来父类对象是不可以访问子类特有方法的,但是转型以后就可以访问了)
Dog dog=(Dog)animal;//向下转型必须还原回本来的类型,如果强行去转成别的,编译没事,但是运行时会报错 ClassCastException
可以用instanceof关键字在向下转型之前进行判断:
if(animal instanceof Dog){
Dog dog=(Dog) animal;
}
10 final关键字
10.1 final修饰类时,该类不能有任何子类(可以有父类),故所有成员方法都不能被覆盖重写:public final class 类名{ ... }
10.2 final修饰方法时,这个方法就是最终方法,不能被子类重写。abstract和final不可同时写(编译器会报错)
10.3 final修饰局部变量时,只能被唯一一次赋值,之后不可变:
final int num1=30;//之后再次赋值会报错
final int num2;num2=30;//此处是第一次赋值,可以,但之后不可再赋值
对于基本类型来说,不可变指的是变量中的数据不可改变
对于引用类型来说,不可变指的是变量当中的地址值不可改变(对象的成员变量的值还是可以被重新set的,只是该对象不可以new出新的)
10.4 final修饰成员变量时,由于成员变量具有默认值,所以用了final后必须手动赋值,不会再给默认值。赋值要么直接赋值,要么通过构造方法赋值(二选一,但是用后者的话,要保证类中所有重载的构造方法都最终会对final的成员变量进行赋值)
11 java四种修饰权限
访问规则:
public protected (default) private
同一个类 √ √ √ √
同一个包 √ √ √
不同包子类 √ √
不同包非子类 √
12 内部类
12.1 编译后内部类会被编译成独立的.class文件,文件名为 外部类$内部类.class ,因此一般类命名不推荐用$
12.2 使用成员内部类的方式
1)间接方式:在外部类的方法中使用内部类,main中再调用外部类的方法间接使用
2)直接方式:外部类.内部类 对象名=new 外部类().new 内部类();
12.3 内部类是可以直接访问外部类所有成员的,但是如果内部类和外部类变量重名时,访问各变量的方法如下:
public class Outer{
int num=10;//外部类成员变量
public class Inner{
int num=20;//内部类成员变量
public void methodInner(){
int num=30;
System.out.println(num);//就近原则
System.out.println(this.num);//访问内部类成员变量
System.out.println(Outer.this.num);//访问外部类成员变量
}
}
}
12.4 局部内部类(一个类定义在一个方法内),只有当前方法可以使用,出了这个方法就无法使用了
12.5 局部内部类如果希望访问所在方法的局部变量,那么这个局部变量必须是有效final的(即该变量要么被final修饰,要么没有但是在使用他之前只被赋值了一次,否则编译报错)
public class Outer{
public void methodOuter(){
int num=10;//所在方法的局部变量
class MyInner{
public void methodInner(){
System.out.println(num);//num之前只被赋值了一次;如果还被赋值第二次将会报错
//从java 8+开始,只要局部变量事实不变,那么final关键字可以省略
//因为new出来的对象在堆中,局部变量跟着方法走在栈中;方法运行结束以后立刻出栈,局部变量也会消失;但是new出的对象会在堆中持续存在,直到垃圾回收。故此时如果内部类想要访问局部变量,将无法得到值。
//但是如果变量是有效final,那么可以直接复制他的值使用,后面他存不存在已经无关紧要,但前提是他的值是确定的
}
}
}
}
12.6 匿名内部类
对于一个接口MyInterface,如果只要使用一次,即可以使用匿名内部类,使用接口名直接创建,但是要在{}中覆盖重写接口中所有的抽象方法
MyInterface obj=new MyInterface(){ //MyInterface是一个接口
@Override
public void meyhod(){
}
}
obj.method();//以往使用接口必须做一个实现类,使用匿名内部类的话就可以省去了
以上使用了匿名内部类,没有匿名对象。如果也用匿名对象的话,可以这样写:
new MyInterface(){ //MyInterface是一个接口
@Overrid
public void meyhod(){
}
}.method(); //同时使用匿名对象(但匿名对象只可以使用一次,故如果接口中还有别的方法要使用,就不应该这样写了)
12.7 接口修饰的对象也可以作为类的成员变量;接口也可以作为方法参数
hero.setSkill(new Skill(){ //hero是类Hero的对象,接口Skill是一个接口,且是Hero的成员变量。这里使用匿名内部类作为参数传入
@Override
public void use(){
...
}
});
public static List<String> addNames(List<String> list){ //java.util.List正是一个接口
}
DOWN 返回