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 返回