内部类
什么是内部类
将一个类定义在另一个类里面,里面那个称之为内部类,外面那个称之为外部类
内部类的分类
- 成员内部类
- 局部内部类
- 匿名内部类
成员内部类
成员内部类格式
class 外部类{
class 内部类{
}
}
成员内部类访问特点
- 内部类可以直接访问外部类的成员,包括私有成员
- 外部类要访问内部类的成员,必须要建立内部类的对象
创建内部类对象格式
外部类名.内部类名 对象名 = new 外部类型().new 内部类型();
代码演示
- 成员内部类演示
package cn.zhuo_01;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 9:12
* @Desc: 成员内部类演示
*/
public class Person {
private boolean live;
public void setLive(boolean live) {
this.live = live;
}
//成员内部类
class Heart{
int sum = 20;
//成员内部类的成员方法
public void jump(){
//内部类可以直接访问外部类的成员,包括私有成员
if(live){
System.out.println("心在跳,似爱情如烈火");
}else {
System.out.println("GG");
}
}
}
//外部类要访问内部类的成员,必须要建立内部类的对象
public void show() {
Heart he = new Heart();
System.out.println(he.sum);
}
}
- 测试类
package cn.zhuo_01;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 9:17
* @Desc: 成员内部类测试
*/
public class Tset {
public static void main(String[] args) {
//创建外部类对象
Person person = new Person();
person.setLive(true);
person.show();
//创建内部类对象
//Person.Heart ph = new Person().new Heart();这里拿不到上面给live的true
//因为这里创建了新的new person() 跟上面的new person()不一样,自然拿不到上面给Person类成员变量的true
Person.Heart ph = person.new Heart();
ph.jump();
}
}
- 注:内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的
.class
文件,但前面冠以外部类的类名和$
符号,如:Person$Heart.class
局部内部类
局部内部类:将一个类定义在一个方法中,该类称之为局部内部类
如何使用局部内部类
只能在该方法内部使用局部内部类(方法与方法之间是有隔离的)
代码演示
package cn.zhuo_02;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 9:24
* @Desc: 局部内部类演示
*/
public class Outer {
//成员变量
int sum = 20;
//成员方法
public void show(){
//局部变量
int num = 10;
//局部内部类
class Inner{
//局部内部类的成员方法
public void method(){
System.out.println("你在笑,说疯狂的人是我");
//可以访问到局部变量和成员变量
System.out.println(num);
System.out.println(sum);
}
}
//只能在成员方法中调用
Inner inner = new Inner();
inner.method();
new Inner().method();//同上
}
}
- 测试类
package cn.zhuo_02;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 9:27
* @Desc: 局部内部类测试
*/
public class Test {
public static void main(String[] args) {
Outer outer = new Outer();
outer.show();
}
}
匿名内部类
匿名内部类是内部类的简化写法,本质是一个 带具体实现的 父类或者父接口的 匿名的 子类对象
使用匿名内部类的前提
匿名内部类必须继承一个父类或者实现一个接口
匿名内部类的格式
new 父类名或者接口名(){
@Override//方法重写
public void method(){
//执行语句
}
};
匿名内部类的使用
以接口为例,三种使用方式
- 接口
package cn.zhuo_03;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 9:33
* @Desc:
*/
public interface FlyAble {
void fly();
void show();
}
- 测试类
package cn.zhuo_03;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 9:34
* @Desc:
*/
public class Test {
public static void main(String[] args) {
//原版:通过定义接口的实现类来实例化接口并调用功能
FlyAble flyAble = new FlyAbleImpl();
flyAble.fly();*/
//匿名内部类使用方法一:一次只能调用一个方法
new FlyAble(){
@Override
public void show() {
System.out.println("我看见爱的火焰闪烁");
}
@Override
public void fly() {
System.out.println("爱如火会温暖了心窝");
}
}.show();
//使用方法二:需要调用多个方法时,调用比较简单
FlyAble flyAble = new FlyAble(){
@Override
public void fly() {
System.out.println("爱如火会温暖了心窝");
}
@Override
public void show() {
System.out.println("我看见爱的火焰闪烁");
}
};
flyAble.fly();
flyAble.show();
//使用方法三:
showFly(new FlyAble() {
@Override
public void fly() {
System.out.println("爱如火会温暖了心窝");
}
@Override
public void show() {
System.out.println("我看见爱的火焰闪烁");
}
});
}
public static void showFly(FlyAble f){
f.fly();
f.show();
}
}
匿名内部类的好处
就是可以不用再写一个实现类来实现接口,可直接使用
引用类型方法的参数和返回值
普通类—作为方法的参数及返回值
普通类—作为方法的形参
- 方法的形参是类名,其实需要的是该类的对象
- 实际传递的是该对象的地址值
普通类—作为方法的返回值
- 方法的返回值类型是类名,其实返回的是该类的对象
- 实际传递的是该对象的地址值
代码演示
- 第一个类
package cn.zhuo_04;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 10:19
* @Desc: 普通类-作为方法的形参 和返回值
*/
public class Student {
public void study(){
System.out.println("试着留盏灯假装陪伴失眠的我");
}
public void show(){
System.out.println("窗口就有等待的效果");
}
}
- 第二个类
package cn.zhuo_04;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 10:19
* @Desc: 普通类-作为方法的形参 和返回值
*/
public class StudentDemo {
//成员方法,把普通类当成一个参数
public void method(Student student){
student.study();
}
//返回值类型为一个类
public Student getStudent(){
//方法的返回值是类名,其实返回的是该类的对象
/*Student student = new Student();
return student;*/
return new Student();
}
}
- 测试类
package cn.zhuo_04;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 10:20
* @Desc: 普通类-作为方法的形参和返回值
*/
public class Test {
public static void main(String[] args) {
//创建对象
StudentDemo st = new StudentDemo();
Student s = new Student();
//方法的形参是类名,其实需要的是该类的对象
st.method(s);
//返回也是一个对象
Student student = st.getStudent();
student.show();
}
}
抽象类—作为方法的参数及返回值
抽象类—作为形参和返回值
- 方法的形参是抽象类名,其实需要的是该抽象类的子类对象
- 方法的返回值是抽象类名,其实返回的是该抽象类的子类对象
代码演示
- 抽象类
package cn.zhuo_05;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 11:48
* @Desc: 抽象类作为形参 和返回值
*/
public abstract class Person {
//抽象类的成员方法
public abstract void study();
public abstract void show();
}
- 抽象类的子类
package cn.zhuo_05;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 12:00
* @Desc: 抽象类作为形参 和返回值
*/
public class Student extends Person{
@Override
public void study() {
System.out.println("已经习惯摆放好两人份的餐桌");
}
@Override
public void show() {
System.out.println("这样看上去就不寂寞");
}
}
- Demo类
package cn.zhuo_05;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 11:48
* @Desc: 抽象类作为形参 和返回值
*/
public class PersonDemo {
//抽象类作为形参
public void method(Person p){
p.study();
}
//返回对象是一个抽象类
public Person getPerson() {
//person是一个抽象类,只能通过多态的方法实例化
/*Person p = new Student();
return p;*/
return new Student();
}
}
- 测试类
package cn.zhuo_05;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 11:48
* @Desc: 抽象类作为形参 和返回值
*/
public class PersonTest {
public static void main(String[] args) {
PersonDemo pd = new PersonDemo();
//抽象类需要一个具体类来实现
//抽象类作为参数,必须实例化
Person p = new Student();//method的参数是一个抽象类,将抽象类以多态的方式实例化
pd.method(p);
//返回的是 new student(),相当于 Person person = new Student();
Person person = pd.getPerson();
person.show();
}
}
接口类—作为方法的参数及返回值
接口作为形参和返回值
- 方法的形参是接口名,其实需要的是该接口的实现类对象
- 方法的返回值是接口名,其实返回的是该接口的实现类对象
代码演示
- 接口
package cn.zhuo_06;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 11:47
* @Desc: 接口类-作为方法的参数及返回值
*/
public interface Love {
public abstract void show();
public abstract void show1();
}
- 接口的实现类
package cn.zhuo_06;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 12:11
* @Desc: 接口类-作为方法的参数及返回值
*/
public class LoveImpl implements Love{
@Override
public void show() {
System.out.println("那是你离开了北京的生活");
}
@Override
public void show1() {
System.out.println("街上的人偶尔会模仿你小动作");
}
}
- Demo类
package cn.zhuo_06;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 11:47
* @Desc: 接口类-作为方法的参数及返回值
*/
public class LoveDemo {
//接口作为参数
public void method(Love love){
love.show();
}
//接口作为返回值
public Love getLove(){
// 接口不能直接返回,需要实例化,多态的方式
// Love love = new LoveImpl();
// return love;
return new LoveImpl();
}
}
- 测试类
package cn.zhuo_06;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 11:47
* @Desc: 接口类-作为方法的参数及返回值
*/
public class LoveTest {
public static void main(String[] args) {
LoveDemo ld = new LoveDemo();
//需要对接口的参数进行实现化,多态的方法
Love love = new LoveImpl();
//参数需要的是一个接口
ld.method(love);
//或 ld.method(new LoveImpl());
Love ldLove = ld.getLove();
ldLove.show1();
}
}
final关键字
概述
为了避免出现随意改写的情况,Java提供了final
关键字,用于修饰不可改变的内容
特点
final
表示不可改变,可用于修饰类、方法和变量
- 类:被修饰的类,不可被继承
- 方法:被修饰的方法,不可被重写
- 变量:被修饰的变量,不能重新赋值,变成了常量
final的使用
- 修饰类
- 格式:
public final class Fu{}
//public class Zi extends Fu{}——错误
//子类不能继承final所修饰的父类
- 修饰方法
- 修饰变量
- 代码演示:
package cn.zhuo_07;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 14:43
* @Desc:
*/
//被 final 修饰的类,不能被继承。
//public final class Fu {
public class Fu{
final int num = 10;
public final void show(){
System.out.println("不能被重写");
}
}
package cn.zhuo_07;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 14:44
* @Desc:
*/
public class Son extends Fu{
//public void show() {} //show方法不能被重写
}
package cn.zhuo_07;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 14:49
* @Desc:
*/
public class Test {
public static void main(String[] args) {
Fu fu = new Fu();
//被 final修饰的变量,不能被重新赋值,变成了常量
//fu.num = 20;
fu.show();
}
}
包的定义及规范
包的定义
- 使用
package
定义包 - 格式:
package 包名;(如果是多级包,中间用.隔开)
注意事项
package
语句必是程序的第一条可执行代码- 一个Java文件中只能有一个
package
语句 - 若无
package
默认表示无包名
类与类之间的访问
- 同一个包下:无需导包,直接访问
- 不同包下:
inport
导包后访问;全类名(包名+类名)访问
注:
package
必须是程序的第一条可执行代码
import
需要写在package
下面
class
需要写在import
下面
分包
- 功能分包
- 模块分包
- 业务模块分层包
权限修饰符
权限概述
public
:公共的protected
:受保护的default
:默认的private
:私有的
不同情况下的不同权限访问情况
代码略,敲好了,懒得复制过来了…
总结
- 四大权限中
public
为最大的权限,private
为最小权限- 所有子类都可以访问父类中
protected
修饰的成员 - 同一个包下的类都可以访问
default
修饰的成员
- 所有子类都可以访问父类中
- 建议:
- 成员变量:
private
—隐藏细节 - 成员方法:
public
—方便调用 - 构造方法:
public
—方便创造对象
- 成员变量:
static关键字
可用来修饰成员变量和成员方法,被修饰的成员是属于类的,而不单是属于某个对象的,也就是说,可以不靠创造对象来调用
static的特点
- 可修饰成员变量、成员方法
- 随着类的加载而加载
- 优先于对象存在
- 被类的所有对象共享
- 可通过类名调用
静态变量
详见代码
静态方法
详见代码
package cn.zhuo_09;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 16:01
* @Desc: 静态变量和静态方法
*/
public class Student {
//非静态变量(动态变量)
int num1 = 10;
//静态变量
static int num2 = 20;
//非静态方法
public void show(){
System.out.println(num1);
System.out.println(this.num1);
System.out.println(num2);
//非静态方法可以访问静态方法也可以访问非静态方法
function();
function2();
}
//静态方法
public static void method(){
//静态不能访问非静态的成员变量
//System.out.println(num1);
//静态中没有 this
//System.out.println(this.num1);
//静态方法可以访问静态的成员变量
System.out.println(num2);
//静态方法不能访问非静态方法
//function();
//静态方法可以访问静态方法
function2();
}
public void function(){
System.out.println("轻而易举就能将我击破");
}
public static void function2(){
System.out.println("那些承诺提起人是你,还是我");
}
}
package cn.zhuo_09;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 16:02
* @Desc:
*/
public class StudentDemo {
public static void main(String[] args) {
Student student = new Student();
System.out.println(student.num1);
//System.out.println(student.num2);//不推荐以此方法访问静态变量
System.out.println(Student.num2);//静态变量,可以通过:类名.变量名 的格式访问
student.show();
Student.method();
}
}
static注意事项
- 静态方法中不能出现
this
关键字 - 静态只能访问静态,非静态可以访问静态也可以访问非静态
调用格式
被static
修饰的成员可以并且建议通过类名访问
- 格式:
类名.变量名;//访问类变量
类名.静态方法名(参数);//调用静态方法
静态变量和成员变量的区别
-
所属不同
- 静态变量属于类,所以也称为类变量
- 成员变量属于对象,所以也称之为实例变量(对象变量)
-
内存中位置不同
- 静态变量存储于方法区的静态区
- 成员变量存储于堆内存中
-
生命周期不同
-
静态变量随着类的加载而加载,随着类的消失而消失
-
成员变量随着对象的创建而创建,随着对象的消失而消失
-
-
调用不同
- 静态变量可以通过类名调用,也可以通过对象来调用
- 成员变量只能通过对象名调用
main方法是静态的
静态代码块
定义在成员位置,使用static
修饰的代码块{ }
- 位置:类中方法外
- 执行:随着类的加载而执行且仅执行一次,优先于main方法和构造方法的执行
- 格式:
public class ClassName{
static {
// 执行语句
}
}
//构造代码块
{
}
- 代码演示:
package cn.zhuo_10;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 20:20
* @Desc: 静态代码块相关
*/
public class Game {
static int age;
static String name;
//构造代码块
{
age = 20;
name = "张三";
System.out.println("那是你离开了北京的生活");
}
//静态代码块:随着类的加载而加载,并且只加载一次
static {
age = 25;
name = "李四";
System.out.println("我以为我爱了 就会留下些什么 纪念那些曲折");
}
public static void show() {
System.out.println("我们快乐的争吵的不舍的分分合合");
}
}
package cn.zhuo_10;
/**
* @Auther: 不学无墅
* @Date: 2023/7/17 20:20
* @Desc:
*/
public class GameTest {
//静态代码块 --> 构造代码块 --> 静态方法
public static void main(String[] args) {
//静态代码块 在 构造代码块 之前执行
//静态代码块属于类,优先于对象存在
Game g = new Game();
//静态代码块随着类的加载而加载,并且只加载一次
//静态代码块会执行,只执行一次
//构造方法每一次实例化对象都会执行
Game g2 = new Game();
//静态方法,不调用不执行
Game.show();
Game.show();
}
}
**注:**静态代码块的主要作用是给类变量进行初始化赋值