关键字的特点:
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
* 方法名称: send
* 参数列表: 1.总共发多少钱 int totalMoney
* 2.分成多少份 int count
*
* */
/*收红包的逻辑,三要素
* 返回值类型:void
* 方法名称:receive
* 参数列表:ArrayList
* */
接口就是一种公共的规范标准!!!
代码中,接口就是多个类的公共规范。
接口是一种引用类型,最重要的内容就是其中的抽象方法;
如何定义一个接口的格式
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.不安全,会引发异常
定义含有泛型的方法:
格式:
修饰符 <泛型> 返回值类型 方法名
还有泛型通配符 **?**之类的