JAVA笔记

关键字的特点:

	1.全部是小写;
	2.有特殊颜色;

标识符=自定义名称

命名规范:
	1.类名规范:首字符大写,后面每个单词首字母大写HelloWorld
	2.变量名规范:首字符小写,后面每个单词首字母大写
	3.方法名规范:同变量名
	
java中两个单引号之间必须有且仅有一个字符,没有字符也不行。
空常量null不能直接用来打印输出

java中的基本数据类型:

整数型: byte short int long
浮点型: float double
字符型: char
布尔型: boolean

引用数据类型:

字符串、数组、类、接口、Lambda

注意点:

	1.字符串不是基本数据类型,而是引用类型
	2.浮点数可能只是一个近似值,并非是精确值;
	3.数据范围与字节数不一定相关,例如float数据范围比long更加广泛,到那时float是4字节,long是8字节
	4.浮点数当中默认double,如果要使用float,需要后缀加F。

变量使用注意点:

	1.对于float和long类型来说,字符后缀F和L不要丢掉
	2.没有进行赋值的变量不能直接使用,一定要赋值之后才能使用。
	3.变量的使用不能超过作用域的范围;
	【作用域】:从定义变量的一行开始,一直到直接所属的大括号结束为止。

byte/short/char 在运算的时候,都会被首先提升为int类型,然后再计算。
	
boolean 类型不能发生数据类型转换!!!!
	
注意!任何数据类型和字符串进行连接时,结果都会变成字符串!!!	
	
只有变量才能使用自增自减符号。	

/*
定义一个方法的格式
public static void 方法名称(){

	方法体。。。

}


*/

右侧的常量结果数值,没有超过左侧范围,所以正确。
这称为“编译器的常量优化”

但是要注意,前提是表达式中没有变量。

IDEA项目结构

项目-project
模块-module
包-package

main:psvm
system.out.println:sout

IDEA 常用快捷键

1. alt + enter :导入包,自动修正代码
2. Ctrl + Y :删除光标所在行
3. ctrl + D :复制光标所在行的内容,插入光标位置下面
4. ctrl + alt + L :格式化代码
5. ctrl + / :单行注释,再按取消注释
6. ctrl + shift + / :选中代码注释,多行注释,再按取消注释
7. alt + ins :自动生成代码,toString,get,set等方法
8. alt + shift +上下箭头,移动到当前代码行。

Java中使用方法的注意事项:

1.方法应该定义在类当中,但是不能再方法中再定义方法,不能嵌套;
2.方法定义的的前后顺序无所谓;
3.方法定义之后不会执行,如果希望执行,一定要调用,单独调用,

函数重载注意事项:

1.与参数列表有关,与返回值类型无关!!!!
2.参数个数,类型不同,参数多类型顺序不同;
3.跟其他无关,包括修饰符!!

这样看的话,数组的使用不就是数据类型中的”重载“使用吗?
有同样的数组名,但是具体的位置不同。

数组有两种初始化:

1.动态初始化:
	int a[] = new int[10];
2.静态初始化:
	数据类型[] 数组名 = new int[](具体内容);
	例:int[] array = new int[]{5,15,25};
		或者直接省略
		int[] array = {5,15,25};

Java的内存需要划分为5个部分:

1.栈(Stack):存放的都是方法中的局部变量
	一旦超出作用域,立即从栈内存中消失;
2.堆(Heap):凡是new出来的东西,都在堆当中
	堆内存里面的东西都有一个地址,16进制
	堆内存里面的数据都有默认值,规则
	整数:0
	浮点数:0.0
	字符:‘\u0000’
	布尔:false
	引用类型:null


3.方法区(Method area):存储.class相关信息,包含方法的信息
4.本地方法栈(Native Method stack):与操作系统相关
5.寄存器(pc register):与CPU相关。

所有的引用类型都可以赋值为null,但是代表里面什么都没有。
如果只是赋值了一个null,但是没有进行new创建,
那么将会发生空指针异常
NullPointerException
原因:忘了new,解决:补上new

如何获取数组的长度?
arr.length

一个方法中可以有0或1个返回值,不能有多个返回值,
如果希望一个方法中产生多个结果数据进行返回,怎么办?
解决方法:使用一个数组作为返回值类型。

面向对象:拿来主义:
用别的类的方法来完成自己需要完成的任务。
从执行者变为指挥者
封装、继承、多态。

类是对象的模板,对象是类的实体。
成员变量、成员方法。
注意!!
面向对象中的成员方法是没有static的!!!
成员变量是定义在类当中,而不是方法中。

面向对象使用步骤:

1.导包:也就是指出需要使用的类,在什么位置

	import 包名称.类名称
	import cn.itcast.day06.demo01.Student;
	注意:对于和当前类同属于一个包的情况,可以省略导包语句。

2.创建
	类名称 对象名 = new 类名称();


3.使用 
	对象名加点。

注意事项:如果成员变量没有进行赋值,那么将会有一个默认值,
规则和数组一样。

栈:各种变量名,包括引用对象变量名
堆:各种new出来的东西,new出引用对象,方法位置是对应的方法区中的函数地址。
方法区:类的各种信息,成员变量和成员方法

Java中引用对象作为实参传递的时候,实质上传递的是对象的地址值。

方法在main函数中调用的时候,从方法区中找是否有对应的方法,
如果有,就开辟空间进栈。

总结:引用对象作为传递参数和返回值的时候,实际上都是
传递的地址值。

成员变量和局部变量的区别:

1.定义的位置不同:
	局部变量:在方法内部
	成员变量:在方法的外部,直接写在类当中。
	
2.作用的范围不一样!!
	局部变量:只有在方法中才能使用
	成员变量:整个类都可以通用

3.默认值不一样:
	局部变量:没有默认值,想要使用必须手动进行赋值
	成员变量:有默认值,规则与数组一样

4.内存的位置不一样:
	局部变量:栈中
	成员变量:堆中
	
5。生命周期不一样:
	局部变量:随着方法进栈,出栈而诞生和消失
	成员变量:随着对象的产生和垃圾回收而诞生和消失。

封装:

1.方法就是一种封装;
2.关键字private也是一种封装。

private关键字的使用:

必要性:定义person的年龄时,无法阻止不合理的数值
解决方法,应该对用户的输入数据进行判断处理
外部类不能直接访问,只能间接访问。

白话,将成员变量用private修饰,
然后通过get获取,set进行设置。

特例:对于boolean值,get方法一定要写成isXxx的形式,
而set方法的形式不变。

this指针:

this指针的变量是当前对象的成员变量。

重要:通过哪个对象调用的方法,那个对象就是this。

通过this,在重名的时候达到区分的效果。

构造方法

1.构造函数的名称和类名称完全一样。大小写一样,是个特例。
2.构造函数不要写返回值类型,连void都不要写。
3.public
4.构造方法不能return一个具体的返回值。
5.如果没有编写任何构造方法,编译器会默认赠送一个构造方法。
6.一旦编写了至少一个构造方法,编译器将不再赠送。所以有多个时,自己要把默认的构造函数写出来

正题:一个标准的类

1.所有的成员变量都要使用private关键字修饰
2.为每一个成员变量编写一对setter和getter方法
3.编写一个无参数的构造方法
4.编写一个全参数的构造方法

Java常用API:

Scanner,Random,ArrayList。

API文档怎么看?

关注3点内容:
1.类名称上面的小字:类所在的包路径;
2.看构造方法,用到哪个看哪个
3.看普通的成员方法

总结:1.包路径2.构造方法3.方法摘要

匿名对象的说明

匿名对象就是只有右边的对象,没有左边的名字和赋值运算符。
new 类名称()
例:new Person().name = "娃哈哈";

注意事项:匿名对象只能使用唯一一次,下次使用必须再创建一个新对象;
使用建议:如果确定一个对象只使用一次,可以使用匿名对象。

同样的匿名对象也可以作为传递参数和返回值。

Random类:

用来生成随机数字,使用起来也是三个步骤:
1.导包2.创建,3.使用
r.nextInt(10),产生0·9之间的伪随机数。

ArrayList类:

数组的长度不可以发生改变;
但是ArrayList集合的长度可以随意变化。

注意事项:

对于ArrayList来说,直接打印得到的不是地址值,而是内容。
如果内容为空,得到的是空的中括号。

常用方法:

public boolean add(E e); //向集合中添加元素
public E get(int index);//从集合中获取元素,index是下标值
public E remove(int index);//从集合中删除元素
public int size(); //获取集合的尺寸长度,返回值是集合的长度

备注:对于ArrayList集合,add操作一定是成功的,但是对于其他集合是不一定的。

注意:泛型只能是引用类型,不能是基本类型。
如果希望向集合中存储基本类型数据,必须使用基本类型对应的包装类型。

byte  Byte
short Short
int   Integer
long  Long
float Float
double Double
char   Character
boolean Boolean

就把对应的引用类型当做基本类型来使用就可以了。

重要:

1.字符串的内容永不可变,是一个常量!!!!!
2.正是因为字符串不可改变,所以字符串可以共享使用
3.字符串效果上相当于char[]字符数组,但是底层原理是byte[]字节数组

创建字符串的常见3+1种方式:

3种构造方法:
	public String(),创建一个空白字符串,不含有任何内容;
	public String(char[] array);//根据字符数组内容来创建对应的字符串。
	public String(byte[] array);//根据字节数组的内容,来创建对应的字符串。
1种直接创建。	

字符串常量池在堆中。

字符串常量池中的字符串对象保存的也是地址值,
实际的值,即内容保存在堆中创建的byte数组中。
地址值,就是这个byte数组的地址。

注意,一旦用了new了,就不是常量池当中了。

1.对于引用类型来说,==进行的是对地址的比较。

常用的方法:
1.如果想要对内容进行比较呢?

	1.用equals方法,区分大小写
	equals方法具有对称性,
	如果比较一个变量和一个常量,推荐把常量写在前面
	为什么,防止出现空指针异常

	2.用equalsIgnoreCase方法,忽略大小写。

2.String中与获取相关的方法

	public int length();// 获取字符串长度
	public String concat(String str);//拼接字符串
	public char charAt(int index);//获取指定索引位置的单个字符
	public int indexOf(String str);//查找参数字符串在本字符串中首次出现的索引位置
	

注意,字符串但凡觉得是变了,一定是创建了一个新的。

3.字符串的截取方法

	public String substrng(int index);//从index到末尾
	public String substring(ins begin,int end);//从begin到end

	范围是左闭右开。

4.字符串的转换相关的方法:

	public char[] toCharArray();//将当前字符串拆分成字符数组作为返回值
	public byte[] getBytes();//获得当前字符串底层的字节数组
	public String replace(CharSequence oldString,CharSequence newString);//将新字符串替换老字符串。

IDEA如何进入引用类型声明定义处?

	1.CTRL+单击引用类型;
	2.ctrl+n,输入引用类型名称,再按ctrl+n

5.字符串分割方法

	public String[] split(String regex);//按照参数的规则,将字符串分为若干部分
	例:
	String str1 = "aaa,bbb,ccc";
    String[] arra = str1.split(",");

    for (int i = 0; i < arra.length; i++) {
        System.out.println(arra[i]);
    }

	注意,split方法的参数实际上是一个“正则表达式”!!!!
	如果用“.”切割,需要“\\.”

static关键字:

对于多个对象共享的数据,可以只存一份,便于修改。
否则,每个对象一份相同的数据,如果修改的时候,每个对象都需要修改。

所以,一旦用了static关键字,那么这样的内容不再属于对象自己,
而是属于类的,所有这个类的对象都可以使用这份数据。


比如,同在一个教室root,则static String room;
使用计数器,private static int count = 0;


如果static修饰成员方法时,就成为了静态方法,
静态方法不属于对象,属于类。

对于静态方法来说,可以通过对象名来调用(不推荐),也可以直接通过类名称来调用。

无论是成员变量还是成员方法,如果有了static,都推荐使用类名称进行调用

注意:对于本类当中的静态方法,调用时可以省略类名称。

注意事项:
1.静态不能直接访问非静态。

原因: 在内存中是先有的静态内容,后有的非静态内容。

2.静态方法中不能用this

原因: this代表当前对象,因为编译器本质上是通过类名调用的静态方法

方法区中有一块独立的内存空间,叫做静态区,存放静态成员变量,

静态代码块:
格式:

public class 类名称{

	static{
		//静态代码块的内容
	}

}

特点:
	当第一次用到本类时,静态代码块执行唯一的一次。

静态内容总是优先于非静态,所以静态代码块比构造方法先执行。

public class Person {


    public Person(){
        System.out.println("构造函数执行");
    }

    static {

        System.out.println("静态代码块执行");
    }

}

静态代码块执行
构造函数执行
构造函数执行

总结:静态代码块的典型用途:
用来一次性地对静态成员变量进行赋值。

Arrays类:

是一个与数组相关的工具类,里面提供了大量的静态方法,
用来实现数组常见的操作。

常用方法:
public static String toString(数组);//将参数数组变为字符串,默认格式
public static vodi sort(数组);//升序排序

如果是数值,sort默认从小到大;
如果是字母,sort默认按字母升序;
如果是自定义类型,需要Comparable或者Comparator接口的支持。

Math类

public static double abs(double num);//绝对值
public static double ceil(double num);//向上取整
public static double floor(double num);//向下取整
public static long round(double num);//四舍五入

Math.PI代表圆周率

继承是多态的前提,如果没有继承,就没有多态

继承主要解决的问题:共性抽取!!!!!

父类,也可以叫基类,超类

继承关系的特点:

1.子类可以拥有父类的内容;实现了代码复用。
2.子类还可以拥有自己专有的内容

父类对象只能使用父类的东西,不能使用子类的东西。

/*
* 在继承关系中,子类就是一个父类,就是说
* 子类可以被当做父类看待
* 定义父类的格式
* public class  父类名称{
* }
*
* 定义子类的格式:
* public class 子类名称 extends 父类名称{
*
* }
* */

在父子类的继承关系中,如果成员变量重名,则创建子类对象时,访问有两种方式

1.直接通过子类对象访问成员变量:

	等号左边是谁,就优先用谁,没有则向上找;
	就像树一样,从叶节点开始,一直向根节点回溯,
	找不到就编译报错。

2.间接通过成员方法访问成员变量:

	该方法属于谁,就优先使用谁,没有则向上找
	例: zi.methodZi();//200
		 zi.methodFu();//100

如何区分父类子类变量重名问题?

父类的成员变量: super.成员变量名
子类的成员变量:this.成员变量名
局部变量:直接写

public class Fu {
    int num = 10;
}

public class Zi extends Fu{
    int num =20;

public void method(){
    int num = 30;
    System.out.println(num);
    System.out.println(this.num);
    System.out.println(super.num);
}
}


public class Demo02ExtendsField {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.method();
    }


}

在父子类继承关系中,创建子类对象,访问成员方法的规则:
创建的对象是谁,就优先用谁,如果没有就向上找。

注意事项:
无论是成员方法还是成员变量,
如果没有都是向上找父类,绝对不会向下找子类!!!

方法的覆盖override
概念:在继承关系中,方法的名称一样,参数列表一样

要注意与重载overload

覆盖特点:创建的是子类对象,则优先使用子类的方法。

方法覆盖的注意事项:

1.必须使用父子类之间方法的名称一样,参数列表也一样
@override,注解,写在方法前面,检测有没有正确覆盖。
起到安全检测的作用。推荐写。

2.子类方法的返回值必须小于等于父类方法的返回值范围!!!

3.子类方法的权限必须大于等于父类方法的权限修饰符!!!!
public > protected > (default) > private
注意,default不是关键字,而是什么都不写,留空。

覆盖重写适用场景:

设计原则:
    对于已经投入使用的类,尽量不要进行修改。
	推荐定义一个新的类,来重复利用其***性内容,
	并且添加改动新内容。

继承中构造方法的访问特点

1.子类构造方法当中有一个默认隐含的super()无参调用,
所以一定是先调用的父类构造,后调用的子类构造。

2.子类构造可以通过super关键字来子类构造调用父类重载构造


public class Zi extends Fu{
	public Zi(){
		super(10);
		System.out.println("子类构造方法");
	}

}

3.super的父类构造调用,
必须是子类构造方法的第一个语句!!!很重要。
不能一个子类构造调用多次super构造。

总结:

	子类必须调用父类构造方法;
	不写则赠送super();
	写了则用指定的super调用;
	super只能有一个;
	必须是第一个

super关键字的用法有3种:

1.在子类的成员方法中,访问父类的成员变量;
2.在子类的成员方法中,访问父类的成员方法;
3.在子类的构造方法中,访问父类的构造方法

this关键字的3种用法:

1.在本类的成员方法中,访问本类的成员变量;
2.在本类的成员方法中,访问本类的另一个成员方法;
3.在本类的构造方法中,访问本类的另一个构造方法。
this(...)调用也必须是第一个语句,唯一一个。
super和this两种构造调用,不能同时使用!!!

Java中继承的特点:

1.一个类的直接父类只能有唯一一个;
2.可以多级继承
3.一个子类的直接父类是唯一的,但是一个父类可以拥有很多个子类

抽象:
如果父类当中的方法不确定如何进行具体{}实现,那么这个方法就应该是一个抽象方法。

抽象方法:加上abstract关键字,去掉大括号,加上分号结束。

抽象类:抽象方法所在的方法必须是抽象类。
抽象类中可以有普通方法。

使用:
1.不能直接创建new抽象类对象;!!!
2.必须用一个子类来继承抽象父类;
3.子类必须覆盖重写抽象父类当中所有的抽象方法!!!
4.创建子类对象进行使用

注意:
1.抽象类中可以有构造方法,提供子类创建对象时,
初始化父类成员使用。
2.抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
3.抽象类的子类,必须覆盖所有的抽象方法!!!
否则,子类也得是抽象类

继承例子:

/*发红包逻辑,三要素
*
* 返回值类型: ArrayList<Integer>
*  方法名称: send
*  参数列表: 1.总共发多少钱 int totalMoney
*             2.分成多少份 int count
*
* */

/*收红包的逻辑,三要素
* 返回值类型:void
* 方法名称:receive
* 参数列表:ArrayList<Integer>
* */

接口就是一种公共的规范标准!!!

代码中,接口就是多个类的公共规范。
接口是一种引用类型,最重要的内容就是其中的抽象方法;
如何定义一个接口的格式
public interface 接口名称{
}

如果是java 7,那么接口中包含的内容有:
1.常量
2.抽象方法
如果是Java 8,还可以额外包括:
3.默认方法
4.静态方法
如果是Java 9,还可以有:
5.私有方法

注意!!!
接口当中的抽象方法必须是两个固定的关键字
public abstract
但是这两个可以省略

接口使用步骤:

1.接口不能直接使用,必须一个实现类来实现接口
格式 
	public class 实现类名称 implements 接口名称{
	}

2.接口的实现类必须要覆盖接口中所有的抽象方法
3.创建实现类的对象,进行使用。

默认方法格式:
public default 返回值类型 方法名称{方法体}
备注:
接口当中的默认方法可以解决接口升级的问题。
例:a接口,b和c都实现了a接口
但是需要添加一个新方法时,如果a接口新添加一个抽象方法
因为实现该接口的所有类都需要实现该接口的所有抽象方法,
所以a,b,c都需要修改,
接口升级,使用默认方法,b,c不需要修改,只需要给a新添加的内容写成一个默认方法就可以了

1.接口的默认方法,可以通过接口实现类对象直接调用
2.接口的默认方法,也可以被接口实现

接口中的静态方法:

注意:不能通过接口实现类的对象来调用接口中的静态方法
正确用法:通过接口名称直接调用其中的静态方法。

接口中的私有方法作用:

通过建立私有方法,抽取接口中多个默认方法中的共有重复代码内容
实现了代码复用。且防止其被实现类对象调用。

接口当中只可以定义常量:
格式: Public static final …
同样这三个关键字也是默认的。可以省略

一旦使用final关键字进行修饰,说明不可变。

注意事项:

1.接口当中常量,必须手动进行赋值,不能不赋值。
2.接口中常量的名称使用完全大写字母,并使用下划线进行间隔
和宏定义常量一样。

3.接口不能有静态代码块或者构造方法
4.一个类可以实现多个接口。
5.如果实现类没有覆盖所有接口中的抽象方法,那么实现类必须是一个抽象类
6.如果实现类所实现的多个接口当中,存在重复的默认方法,
那么实现类一定要对冲突的默认方法进行覆盖重写。
7.优先级问题,一个类如果父类当中的方法和接口当中的默认方法实现了冲突
优先使用父类当中的方法!!!

接口和接口之间是多继承的,继承用extends
注意:

1.多个父接口当中的抽象方法如果重复,没关系,因为没有方法体;
2.多个父接口当中的默认方法如果重复,有关系,
因为默认方法是有方法体的,内容很可能不同,产生冲突
所以子接口必须进行默认方法的覆盖重写,并且必须带有default关键字

多态性

继承是多态的前提和基础。
多态性是针对对象而言的,如。小明是一个对象。
他既有学生形态,也有人类形态。
一个对象拥有多种形态,就叫多态性。

代码当中体现多态性,其实就是一句话
父类引用指向子类对象。

父类名称 对象名 = new 子类名称();
或者
接口名称 对象名 = new 实现类名称();

左父右子就是多态!!!!

注意:成员变量是不能进行覆盖的,所以实际多态调用的时候和成员方法的调用结果不同
=左边是什么就是谁的成员变量

总结:

1.直接通过对象名称访问成员变量,看等号左边是谁,优先用谁,没有则向上找
2.间接通过成员方法访问成员变量,看该方法属于谁,优先用谁,没有则向上找。

在多态的代码中,成员方法的访问规则是:
看new的是谁,就优先用谁,没有则向上找。

成员方法口诀:编译看左边,运行看右边。
成员变量口诀:编译看左边,运行还看左边。

多态写法的好处:
无论右边new的时候换成哪个子类对象,等号左边调用方法都不会改变。

1.对象的向上转型,就是多态写法
父类名称 对象名 = new 子类名称();

含义:创建了一个子类对象,将其看做父类看待使用。
所以,向上转型一定是安全的。
类似:int-》double
弊端:对象一旦向上转型,就无法调用子类原本特有的内容!!!

解决方案:用对象的向下转型--还原!!!
格式: 子类名称 对象名 = (子类名称)父类对象;
含义:将父类对象,还原为本来的子类对象。

注意事项: 
	1.必须保证对象本来创建的时候就是猫,才能向下转型为猫
	2.如果对象创建的时候本来不是猫,现在非要向下转型成为猫,就会报错。
	

public class Demo01Main {
    public static void main(String[] args) {
        Animal animal = new Cat();
        animal.eat();

        Cat cat = (Cat)animal;
        cat.drink();

    }

}

类似于强制类型转换。

那么问题来了,如何才能知道一个父类引用的对象,
本来是什么子类呢?
格式:
对象 instanceof 类名称
这样会得到一个boolean值结果,
也就是判断前面的对象能不能当做后面类型的实例。

public class Demo01Main {
    public static void main(String[] args) {
        Animal animal = new Cat();
        animal.eat();

        if(animal instanceof Cat){
            Cat cat = (Cat)animal;
            cat.drink();
        }

    }

}

//所以向下转型时,一定要多加判断。

//193,194

final关键字代表最终,不可改变的

常见4种用法:
1.修饰一个类;
		含义:当前这个类不能有任何子类(太监类)
		但是一定有父类,object
		理所当然的,其中所有的成员方法都无法进行覆盖,
		因为没儿子
		
2.修饰一个方法;
	当final关键字用来修饰一个方法时,
	这个方法就是最终方法,也就是不能覆盖重写。

3.修饰一个局部变量;
	一次赋值,终生不变。


4.修饰一个成员变量。
	推荐直接赋值。
	不然需要每个重载的构造函数中都赋值。

注意事项: 对于类、方法来说,
abstract关键字和final关键字不能同时使用,因为矛盾。

”不可变“:

对于基本类型来说,不可变是说变量当中的数据不可改变;
对于引用类型来说,不可变是说变量当中的地址值不可改变。

笔记本电脑案例

1.笔记本电脑有USB接口;
2.定义USB接口,具备基本的开***能和关闭功能;
3.鼠标和键盘想要在笔电上使用,需要遵循USB规范,实现USB接口;

分析:
1.USB接口,包含打开设备功能、关闭设备功能;
2.笔记本类,包含开机功能、关机功能、使用USB设备功能;
3.鼠标类,要实现USB接口,并具备点击的方法;
4.键盘类,要实现USB接口,并具备敲击的方法;

内部类:

一个类用来包含一个事物的。
如果一个事物的内容包含另一个事物,
那么这就是一个类内部包含另一个类。
例如:身体和心脏的关系,汽车和发动机的关系
	心脏脱离身体没有用处,发动机脱离汽车也没有用处。

分类:

1.成员内部类;
2.局部内部类(包含匿名内部类)

成员内部类定义格式

		修饰符 class 类名称{
			修饰符 class 类名称{
				。。。
			}
		}
	

public class Body {//外部类

public class Heart{//成员内部类
    public void beat(){
        System.out.println("心脏跳动");
    }
}

public void methodBody(){
    System.out.println("外部类的方法");
}

}

注意:内用外,随意;外用内,需要内部类对象。

如何使用成员内部类,有两种方法:

1.间接方式:
	在外部类的方法的当中,使用内部类,然后main只是调用
	外部类的方法。
	
public class Body {//外部类

public class Heart{//成员内部类
    public void beat(){
        System.out.println("心脏跳动");
    }
}

public void methodBody(){
    System.out.println("外部类的方法");
    new Heart().beat();
}
}

public class Demo01InnerClass {
    public static void main(String[] args) {
        Body body = new Body();
        body.methodBody();
    }

}		

2.直接方式:
需要记公式:
外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();

	**总体看,就是外.内。**


public class Demo01InnerClass {
    public static void main(String[] args) {
        Body body = new Body();
        body.methodBody();

        Body.Heart heart = new Body().new Heart();
        heart.beat();
        
    }

}

内部类当中对于同名变量如何区分使用?

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);//外部类的成员变量 
        }
    }
    
}

局部内部类:
如果一个类是定义在一个方法内部的,那么这就是一个局部内部类
“局部”,只有当前所属的方法才能使用它,
出了这个方法外面就不能用了。

格式:

修饰符 class 外部类名称{
	修饰符 返回值类型 外部类方法名称(参数列表){
		class 局部内部类名称{
			//...
		}
	
	}


}


public class Outer {
    public void methodOuter(){
        class Inner{
            int num = 10;
            public void methodInner(){
                System.out.println(num);
            }


        }
        Inner inner = new Inner();
        inner.methodInner();

    }


}

public class DemoMain {

public static void main(String[] args) {
    Outer obj = new Outer();
    obj.methodOuter();
}

}

注意:局部内部类的对象只可以new在定义该类的成员方法中。

小结:

类的权限修饰符:
1.外部类:public / default
2.成员内部类:public / protected / default / private
3.局部内部类:什么都不能写。

注意:局部内部类,如果希望访问所在方法的局部变量,
那么这个局部变量必须是【有效final的】!!!

为什么不能变?原因:与生命周期有关

1.new出来的对象在堆内存当中;
2.局部变量是跟着方法走的,在栈内存当中。
3.方法运行结束之后,立刻出栈
4.new出来的对象会在堆中持续存在,直到垃圾回收为止。

就是局部变量已经死了,但是new出来的内部类对象还活着,
如果这个对象还想使用这个变量怎么办?
所以保证了这个局部变量是final,不可变值,虽然这个局部变量消失了
但是他的拷贝份还在,而且值是一样的,这样就可以了。

匿名内部类:重要

//如果接口的实现类,或者是父类的子类,
只需要使用唯一的一次,那么这种情况下,
就可以省略掉该类的定义,而改为使用匿名内部类。

匿名内部类格式:

接口名称 对象名 = new 接口名称(){
	//覆盖重写所有的抽象方法。
};


public class DemoMain {
    public static void main(String[] args) {
       /* MyInterface myInterface = new MyInterfaceImpl();
        myInterface.method();*/
       MyInterface obj = new MyInterface() {
           @Override
           public void method() {
               System.out.println("匿名内部类实现的方法");
           }
       };

    }

}

可以省掉一个类的单独定义。

对匿名内部类格式进行解析:

1.new 代表创建对象的动作;
2.接口名称就是匿名内部类需要实现哪个接口;
3.{。。。}这才是匿名内部类的内容

注意事项:

1.匿名内部类在创建对象的时候,只能使用唯一的一次,
如果希望多次创建对象,而且类的内容一样的话,那么久必须
使用单独定义的实现类了。
2.匿名对象,在调用方法的时候,只能调用唯一的一次;
如果希望同一个对象,调用多次的方法,只能调用唯一的一次
3.匿名内部类是省略了实现类/子类名称,
但是匿名对象是省略了对象名称
强调:匿名内部类和匿名对象不是一回事!!

一个类可以作为成员变量类型,一个接口也可以作为成员变量类型。

Object类
java.lang.Object
每个类都使用Object作为超类

Object类中的toString()直接打印的是对象在堆中的地址值。
所以需要重写这个方法。相对应的,一个对象直接打印出来不是地址,说明就是重写了toString方法

System类

Calendar类

StringBuilder类
字符串缓冲区,可以提高字符串的操作效率
看做一个长度可以变化的字符串
底层是一个数组,但是没有被final修饰,可以改变长度。
append方法返回的是this,调用方法的对象。

String类
是常量,值在创建之后不能再改变;
字符串的底层是一个被final修饰的数组,不能改变是一个常量

Iterator迭代器

就是Collection集合元素的通用获取方式
在取元素之前先要判断集合中有没有元素,如果有,
将元素取出,继续再判断。。。。

hasNext方法,next方法,

迭代器是一个接口,无法直接使用,需要使用Iterator类的实现类对象
Collection接口中有一个方法iterator方法,这个方法返回迭代器的实现类对象
使用步骤: 
	1.多态创建;
	2.使用hasNext方法判断有没有下一个元素;
	3.使用next方法取出集合中的下一个元素。


增强for循环,也叫for each循环。

有点像C++中的auto
例如:  for (String i:collection) {
			System.out.println(i);
		}

注意: 
	这种for循环只能是collection或者数组
	只能作为遍历。

泛型:

泛型是一种未知的类型,当我们不知道使用什么数据类型的时候,
可以使用泛型。
泛型也可以是一个变量,用来接收数据类型。
E e Element 元素
T t Type 类型 

例如: ArrayList集合在定义的时候,
不知道集合中都会存储什么类型的诗句,使用类型使用泛型。

对比使用泛型和不使用泛型的优缺点:
1.创建集合对象,使用泛型:
好处:1.避免了类型转换的麻烦,存储的是什么类型,取出的就是什么类型;
	  2.把运行期异常提升到了编译器。

2.不使用泛型
	1.集合默认Object类型,可以存储任意类型数据
	2.不安全,会引发异常

定义含有泛型的方法:
格式: 
	修饰符 <泛型> 返回值类型 方法名

还有泛型通配符 **?**之类的