1.继承
(1).父类非私有的成员,子类可以直接访问;父类私有的成员,子类想要访问,父类需要提供公共方法。
父类base:
package com.qhx.extend_;
//父类
public class Base {
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
public Base() {
System.out.println("base0....");
}
public void test100() {
System.out.println("test100");
}
protected void test200() {
System.out.println("test200");
}
void test300() {
System.out.println("test300");
}
private void test400() {
System.out.println("test400");
}
//n4是私有的,可以提供公共方法,让子类得到n4
public void getn4(){
System.out.println(n4);
}
}
子类sub:
package com.qhx.extend_;
public class Sub extends Base{
public Sub(){
System.out.println("sub()...");
}
public void sayok(){
System.out.println(n1+n2+n3);//n4是私有属性
test100();
test200();
test300();
//test400();父类的私有方法,子类不能访问
getn4();//通过公共方法得到n4
}
}
测试:
package com.qhx.extend_;
public class ExtendsDetail {
public static void main(String[] args) {
Sub sub=new Sub();
sub.sayok();
}
}
(2).子类必须调用父类的构造器,完成父类初始化。
(3).创建子类对象时,会默认先调用父类的无参构造器;如果父类没有无参构造器,需要在子类构造器中使用super()来规定要调用父类那个构造器。
package com.qhx.extend_;
public class ExtendsDetail2 {
public static void main(String[] args) {
z z1=new z();
System.out.println("对象2:");
z z2=new z("qwq");
}
}
class f{
private String name;
public f(){
System.out.println("父类无参构造器");
}
public f(String name){
this.name=name;
System.out.println("父类name构造器");
}
//set,get就不写了,主要看构造器
}
class z extends f{
public z(){
//super();默认调用父类无参构造器
super("aaa");//指定调用父类有参构造器
//参数随便写一个,如果对象自己有用name
System.out.println("子类无参构造器");
}
public z(String name){
super(name);
System.out.println("子类name构造器");
}
}
2.super关键字
(1).访问父类属性
super.属性名
(2).访问父类方法
super.方法名(参数列表);
(3).访问父类构造方法
super(参数列表)
只能写一次,只能放在第一行
(4).super可以访问父类的父类,采用就近原则
3.重写
(1).方法重写
1).子类的方法名字,参数个数要与父类一致
2).子类方法的返回类型要和父类方法返回值一致,或是子类
3).子类方法不能缩小父类方法的权限
(2).属性没有重写之说
访问属性看编译类型,访问方法看运行类型
先编译,后运行,如果访问方法,先看子类再看父类
public class a {
public static void main(String[] args) {
AA a=new BB();
System.out.println(a.n);//输出多少,输出1
//访问属性看编译类型
}
}
class AA{//父类
public int n=1;
}
class BB extends AA{//父类
public int n=10;
}
4.多态
(1).方法多态
方法重写
方法重载
都体现多态
(2).对象多态
编译类型=运行类型;
例:主人给动物喂食物
master类
package com.qhx.poly_;
public class Master {
public String name;
public Master(String name){
this.name=name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//多态
public void feed(Animal animal,Food food){
System.out.println("主人"+name+"给"+animal.getName()+"喂"+food.getName());
}
}
animal类
package com.qhx.poly_;
public class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public void cry(){
System.out.println("动物叫");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Cat extends Animal{
public Cat(String name) {
super(name);
}
public void cry(){
System.out.println("小猫喵喵叫");
}
}
class Dog extends Animal{
public Dog(String name) {
super(name);
}
public void cry(){
System.out.println("小狗旺旺叫");
}
}
food类
package com.qhx.poly_;
public class Food {
public String name;
public Food(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Fish extends Food{
public Fish(String name) {
super(name);
}
}
class Bone extends Food{
public Bone(String name){
super(name);
}
}
测试类
package com.qhx.poly_;
public class poly01 {
public static void main(String[] args) {
Master master=new Master("tom");
// 对象多态
Animal animal=new Cat("小花猫");
// 编译类型=运行类型
animal.cry();//运行时调用的是Cat中的cry方法
// 运行时animal的运行类型是cat
Food food=new Fish("小黄鱼");
master.feed(animal,food);
Dog dog = new Dog("大黄");
Bone bone=new Bone("骨头");
// master.feed(animal,bone);
}
}
(3).向上转型
先编译,再运行。
编译通过,运行时方法先看子类,再看父类
package com.qhx.poly_.detail;
public class polyDetail {
public static void main(String[] args) {
//向上转型
//可以访问父类的成员,遵守访问权限
//不能访问子类的私有方法
Object obj=new cat();//可以,object也是cat的父类
animal animal1 = new cat();
//animal1.catmouse();错误
//编译就不通过,编译时看animal,而catmouse是cat特有的方法
animal1.eat();//通过
//编译通过,然后看运行类型是cat类,先调用cat中的eat方法
//如果cat里面没有eat方法,再看父类
}
}
(4).向下转型
注意向下转型要和向上转型的运行类型一致
package com.qhx.xx;
public class detail {
public static void main(String[] args) {
Animal animal = new Cat();
//向上转型,可以访问子类父类都有的方法,不能访问子类的特有方法
System.out.println(animal.age);//10
Cat cat=(Cat)animal;
//向下转型,可以访问子类特有方法
System.out.println(cat.age);//20
//属性没有重写之说,直接看编译类型
}
}
class Animal{
public int age=10;
public void eat(){}
}
class Cat extends Animal{
public int age=20;
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public void zhua(){
System.out.println("猫抓老鼠");
}
}
(5).动态绑定机制
动态绑定看运行类型
当调用对象的方法时,该方法会和该对象的内存地址绑定,
当调用对象属性时,没有动态绑定机制
public class c {
public static void main(String[] args) {
E e=new F();
//System.out.println(e.sum());//30
System.out.println(e.sum1());//40
//如果子类没有sum()函数
System.out.println(e.sum());//30
//去调用父类sum()
//但是getn()子类里有,会和e绑定,所以调用子类getn(),n=20
//再加10>30
}
}
class E{
public int n=10;
public int sum(){
return getn()+10;
}
public int sum1(){
return n+10;
}
public int getn(){
return n;
}
}
class F extends E{
public int n=20;
// public int sum(){
// return getn()+20;
// }
public int sum1(){
return n+10;
}
public int getn(){
return n;
}
}
(6). 多态数组
应用实例:现有一个继承结构如下:要求创建1个Person对象、2个Student 对象和2个
Teacher对象,统一放在数组中,并调用每个对象say方法.如何调用子类特有的方法,比如
Teacher有一个 teach, Student有一个, study。怎么调用?
向下转型才能访问子类的特有方法
public class b {
public static void main(String[] args) {
Person p[]=new Person[5];
p[0]=new Person("a",12);
p[1]=new Student("b",13);
p[2]=new Student("c",13);
p[3]=new Teacher("d",40);
p[4]=new Teacher("e",40);
for (int i = 0; i < p.length; i++) {
p[i].say();
if(p[i] instanceof Student){
((Student)p[i]).study();
}else if(p[i] instanceof Teacher){
((Teacher)p[i]).teach();
}else {
System.out.println("没有");
}
}
}
}
class Person{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void say(){
System.out.println("person的say方法");
}
public String getName() {
return name;
}
}
class Student extends Person{
public Student(String name, int age) {
super(name, age);
}
public void study(){
System.out.println("学生"+getName()+"正在学习");
}
public void say(){
System.out.println("student的say方法");
}
}
class Teacher extends Person{
public Teacher(String name, int age) {
super(name, age);
}
public void teach(){
System.out.println("老师"+getName()+"正在教学");
}
public void say(){
System.out.println("teacher的say方法");
}
}
(7).多态参数
上面给动物喂食
5.instanceof方法和==和equals方法和hashCode()和toString方法
(1).instanceof
xx instanceof XX,判断xx的运行类型是不是XX类型,或子类型
System.out.println(cat instanceof Cat);//true
System.out.println(cat instanceof Object);//true
(2).==
可以判断基本类型和引用类型
判断基本类型看值是否相等
判断引用类型看地址是否相同
package com.qhx.equals_;
public class a {
public static void main(String[] args) {
int n=10;
double n2=10.0;
System.out.println(n==n2);//true
B b = new B();
B a=b;
B c=b;
System.out.println(a==c);//true
}
}
class B{}
(3).equals
equals是obj里的方法,只能判断引用类型,地址是否相同 但是子类中往往重写该方法,用来判断内容相等
public class b {
public static void main(String[] args) {
//equals是obj里的方法,只能判断引用类型,地址是否相同
//但是子类中往往重写该方法,用来判断内容相等
A a = new A();
A b=new A();
System.out.println(a.equals(b));//false
//obj里的equals方法,判断地址
System.out.println("aa".equals("bb"));//false
//string里的equals方法判断内容
}
}
class A{
}
(4).hashCode()
返回对象的hashCode编码
编码是通过地址号来的
public class hashCode_ {
public static void main(String[] args) {
A a1=new A();
A a2=a1;
System.out.println(a1.hashCode()==a2.hashCode());
//true
}
}
class A{
}
(5).toString()
默认返回:全类名+@+哈希值的十六进制
子类往往重写此方法
输出一个对象时默认调用该方法
public class b {
public static void main(String[] args) {
A a1=new A();
System.out.println(a1);
//A类不重写toString,输出com.qhx.toString_.A@1e643faf
//A类重写,输出 "我重写tostring方法"
}
}
class A{
public String toString(){
return "我重写tostring方法";
}
6.static关键字
(1).类变量/静态变量
static声明,可以被所有对象实例访问共享,也可以被类名访问
当所有对象都要共享一个变量时,使用
遵守访问权限
package com.qhx.static_;
public class ChildGane {
public static void main(String[] args) {
Child a1 = new Child("a");
a1.join();
a1.count++;
Child a2 = new Child("b");
a2.join();
a2.count++;
Child a3 = new Child("c");
a3.join();
a3.count++;
System.out.println(Child.count);
System.out.println(a1.count);//3
System.out.println(a2.count);//3
System.out.println(a3.count);//3
}
}
class Child{
private String name;
//静态变量,类变量,会被child对象所有的实例共享
//类变量可以通过类名直接访问
public static int count=0;
public void join(){
System.out.println("加入游戏");
}
public Child(String name) {
this.name = name;
}
}
(2).静态方法/类方法
类名和对象实例都可以访问静态方法
静态方法可以访问静态属性,非静态方法也可以访问静态属性
非静态成员可以访问静态和非静态
静态方法中没有this
静态方法只能访问静态成员,不能访问普通成员
package com.qhx.static_;
public class StudentFee {
public static void main(String[] args) {
Stu stu1 = new Stu();
//类名可以访问静态方法和静态变量
//实例对象也可以访问静态方法和静态变量
//stu1.getFee(100);对
Stu.getFee(100);
Stu stu2 = new Stu();
Stu.getFee(200);
Stu.showFee();
}
}
class Stu{
public static int fee=0;
//静态方法可以访问静态属性
//静态方法也可以
public static void getFee(int f){
System.out.println(Stu.fee+=f);
}
public static void showFee(){
System.out.println(Stu.fee);
}
}
7.main方法
public class a {
public static void main(String[] args) {
//public 不在一个类中,设为public
//main方法调用不需要创建对象,所以是static
//
//main方法中的参数如何传递进去
//在程序执行的时候 java a tom jabk smail
//传递3个参数
}
}
查看参数,看这个文章
8.代码块
代码块分为两种,static修饰的静态代码块,和不被修饰的非静态代码块
普通代码块
(1).普通代码块会在创建对象时被调用,每创建一次,调用一次
(2).代码块写在类里面
(3).访问类的静态成员,普通代码块不会被调用,静态代码块会被调用
public class a {
public static void main(String[] args) {
Mover m1=new Mover("喜羊羊");
Mover m2=new Mover("喜羊羊",12);
}
}
class Mover{
public String name;//名字
public int price;//价格
{
System.out.println("电视开始了");
System.out.println("电视广告");
System.out.println("电视结束");
}
public Mover(String name) {
// System.out.println("电视开始了");
// System.out.println("电视广告");
// System.out.println("电视结束");
//上面代码块非静态每次都会被调用
this.name = name;
}
public Mover(String name, int price) {
// System.out.println("电视开始了");
// System.out.println("电视广告");
// System.out.println("电视结束");
//上面代码块非静态每次都会被调用
this.name = name;
this.price = price;
}
}
静态代码块:
什么时候静态代码块会被调用:类加载的时候,下面都是
(1).创建对象实例会被调用
(2).创建子类对象,父类代码块也会被调用,父类先被加载
(3).访问静态成员时
(4).静态代码块之后被调用一次,之后就失效了
重要:
在一个类中的执行流程
(1).先执行静态代码块,和静态属性,谁在前面谁先来
(2).再执行普通代码块和普通属性,谁在前面谁先来
(3),最后调用构造器
在多个继承类的执行流程
(1).父类静态代码块,和静态属性初始化
(2).子类静态代码块,和静态属性初始化
(3).父类普通代码块和普通属性初始化
(4).父类构造器
(5).子类普通代码块和普通属性初始化
(6).子类构造器
在子类构造器中隐藏super()和子类的普通代码块
先完成类的加载,也就是静态初始化
9.单例设计模式
某个类中只有一个实例对象
饿汉单例设计模式
步骤:
//1.构造器私有化
//2.在类的内部创建一个静态对象
//3.对外暴露一个静态方法
//4.通过静态方法返回这个对象
//只有修饰为public static其他类才可以直接调用,私有的静态对象,就获取到了
public class a {
public static void main(String[] args) {
GirlFriend gril=GirlFriend.getInstance();
}
}
class GirlFriend{
//1.构造器私有化
//2.在类的内部创建一个静态对象
//3.对外暴露一个静态方法
//4.通过静态方法返回这个对象
//只有修饰为public static其他类才可以直接调用,私有的静态对象,就获取到了
private String name;
private static GirlFriend gf=new GirlFriend("qwq");//
private GirlFriend(String name) {
this.name = name;
}
public static GirlFriend getInstance(){
return gf;
}
}
懒汉单例设计模式
//1.构造器私有化
//2.创建一个静态私有空对象
//3.创建一个静态公用方法,判断对象是否为null,如果是创建对象,不是返回对象
public class b {
public static void main(String[] args) {
G g1=G.returnG();
System.out.println(g1.toString());
G g2=G.returnG();
//对象之后创建一次g1=g2
}
}
class G{
private String name;
private static G g;
//类加载的时候构造器不会被调用,静态代码块会被调用
private G(String name) {
this.name = name;
}
public static G returnG(){
if (g==null){
g=new G("aaa");
}
return g;
}
public String toString() {
return name;
}
}
10.final关键字
(1).可以修饰属性,方法,局部变量
什么时候使用final关键字
(1).不希望类被继承时
(2).不希望方法被重写时
(3).不希望某个属性被修改时
(4).不希望某个局部变量被修改时
(5).不能修饰构造器
细节:
(1).final修饰的属性必须初始化,可以在定义时,构造器,代码块中初始化
(2).静态属性初始化要在定义时,静态代码块中。
package com.qhx.final_;
public class a {
public static void main(String[] args) {
Y y=new Y(1);
y.gets();
}
}
class Y{
private int r;
//1.在定义时被初始化
//public final static double PI=3.14;
public final static double PI;
public Y(int r) {
this.r = r;
}
//2.在静态代码块中
static {
PI=3.14;
}
public void gets(){
System.out.println(2*PI*r);
}
}
11.抽象类
什么是抽象类
1.一个类存在抽象方法,这个类就是抽象类;抽象类不一定有抽象方法
2.抽象方法和空方法不一样 ,抽象方法没有方法体,也就是没有花括号 ,空方法有方法体
3.抽象类和抽象方法使用abstract修饰
4.抽象类不能被实例化
5.如果一个类继承了抽象类,那他必须重写抽象类中所以的抽象方法,除非他自己也声明为抽象类
6.抽象方法不能使用private,static,final来修饰,与重写违背 ,static修饰方法,可是抽象方法没有方法体
package com.qhx.abstract_;
public class Abstract01 {
public static void main(String[] args) {
// new Aniaml();错误,1.抽象类不能被实例化
}
}
abstract class Aniaml{
private String name;
//2.abstract不能修饰属性,只能修饰方法和类
public Aniaml(String name) {
this.name = name;
}
//父类方法不确定
//抽象方法和空方法不一样
//3.抽象方法没有方法体,也就是没有花括号
//空方法有方法体
//抽象方法
public abstract void eat();
//普通方法
public void hi(){};
}
abstract class A{
//4.抽象类,可以没有抽象方法
}
abstract class B{
//5.有抽象方法一定是抽象类
public abstract void hello();
}
//6.抽象类和普通类一样,可以有构造器
应用:模板设计模式
把一样的提取出来,不一样的写成抽象方法。
public class test1 {
public static void main(String[] args) {
Sub sub = new Sub();
sub.calculateTime();
}
}
abstract class Template{
public abstract void job();
public void calculateTime(){
long start=System.currentTimeMillis();
job();//动态绑定
long end=System.currentTimeMillis();
System.out.println("执行时间"+(end-start));
}
}
class Sub extends Template{
@Override
public void job() {
long num=0;
for (int i = 1; i <= 800000; i++) {
num+=i;
}
}
}
12.接口
1.定义接口interface
(1).jdk7之前接口里的方法都是抽象方法,jdk8以后可以有静态方法和默认实现方法
(2).抽象方法可以省略abstract
(3).默认实现方法要用default修饰
public interface Usb {//接口
public static final int n1=100;//等价int n1=100
//默认方法
default public void lian(){
System.out.println("连接成功");
}
//静态方法
static public void n1(){
System.out.println("10");
}
//抽象方法
public void start();
public void end();
}
细节:
(1).接口中的方法都是public方法
(2).一个类可以实现多个接口
(3).接口中的属性只能是public static final的,int n1=1;等价于public static final int n1=1;
(4).访问接口属性:接口名.属性名
(5).接口不能继承其他类,但是能继承其他接口
class a implements b,c{
}
interface a extends b,c{
}
2.实现接口implement
接口里的抽象方法都要实现,快捷键alt+enter(没设置呢)
除非实现接口的类是抽象类,可以不用实现接口方法
public class Phone implements Usb{
public void start(){
System.out.println("手机开始工作");
}
@Override
public void end() {
System.out.println("手机停止工作");
}
}
3.接口使用场景
3个人分别编写三个类完成对mysql,oracle,db2的连接
每个人写的方法名字可能都不一样
使用接口可以规定名字必须是什么
实现:
public class interface02 {
public static void main(String[] args) {
Mysql mysql = new Mysql();
t(mysql);
OracleDB oracleDB = new OracleDB();
t(oracleDB);
}
public static void t(DBinterface db){
db.connect();
db.close();
}
}
接口:
public interface DBinterface {
public void connect();
public void close();
}
mysql连接类:
public class Mysql implements DBinterface{
public void connect(){
System.out.println("连接mysql");
}
@Override
public void close() {
System.out.println("关闭mysql");
}
}
4.练习
5.继承类和实现接口区别
实现接口:实现一些接口中的方法;那个类需要接口中的方法,哪个类实现接口;补充父类没有的方法
继承:实现父类的一些方法
class a extends b implements c,d{
}
6.接口多态
(1).多态参数
1).上面Compater类的work方法的形参是Usb类型的,既可以接受手机类对象,又可以接收其他类对象;只有是实现了接口的类都可以接收
public class interface01 {
public static void main(String[] args) {
//
Phone phone = new Phone();
Compater compater = new Compater();
Camera camera = new Camera();
compater.work(phone);
compater.work(camera);
}
}
2).接口类型的变量可以指向实现接口的实例
public class interface03 {
public static void main(String[] args) {
IF if1=new Mon();
IF if2=new Car();
}
}
interface IF{
}
class Car implements IF{}
class Mon implements IF{}
(2).多态数组
Usb类型的数组,存放Phone和相机对象,Phone类还有一个对象方法call(),请变量Usb数组,如果是Phone对象,要调用Usb接口的方法,还要调用call()方法。
public class interface04 {
public static void main(String[] args) {
Usb u1[]=new Usb[2];
u1[0]=new Phone();
u1[1]=new Xji();
for (int i = 0; i < u1.length; i++) {
u1[i].com();//动态绑定
if (u1[i] instanceof Phone){
((Phone) u1[i]).call();
}
}
}
}
interface Usb{
public void com();
}
class Phone implements Usb{
public void com(){
System.out.println("打开手机");
}
public void call(){
System.out.println("打电话");
}
}
class Xji implements Usb{
@Override
public void com() {
System.out.println("打开相机");
}
}
(3).多态传递
public class interface05 {
public static void main(String[] args) {
IA ia=new Teacher();
IB ib=new Teacher();
}
}
interface IA{}
interface IB extends IA{}//IB继承IA
class Teacher implements IB{//Teacher继承IB,IB继承IA,这样IA也可以创建Teacher类型的对象
}
7.练习
interface A{
int n=1;
}
class B{
int n=2;
}
public class C extends B implements A{
public void pN(){
//访问接口的:接口名.n
//访问父类的:父类名.n
System.out.println("接口的n"+A.n);
System.out.println("父类的n"+super.n);
}
public static void main(String[] args) {
new C().pN();
}
}
13.内部类
有四种内部类:局部内部类,匿名内部类,成员内部类,静态内部类
1.什么是内部类
被其他类包裹的类叫内部类
包裹他的类叫外部类
剩下的叫外部其他类
2.局部内部类
记住:他是定义在方法和代码块中,本质还是一个类
public class LocalInnerClass {//7.外部其他类,不能访问内部类
public static void main(String[] args) {
Outer02 outer02 = new Outer02();
outer02.m1();
}
}
class Outer02{//外部类
private int n1=1;
public void m2() {//私有方法
System.out.println("m2方法。。。");
}
public void m1 () {//方法
class Inner02 {//局部内部类
//1.可以访问外部类的所以成员和方法,包括私有的
//2.不能添加访问修饰符,因为是局部变量,但是可以用final修饰
//3.作用域:局部内部类只在方法和代码块中
private int n1=10;
public void f1() {
//4.局部内部类直接访问外部类的成员
//8.如果外部类和局部内部类的成员重名时,默认就近原则,如果想访问外部类成员,使用外部类.this.成员
System.out.println(n1);//10
System.out.println(Outer02.this.n1);//1
//n1不是静态的,要用this访问
//Outer02.this本质就是外部类对象,即哪个对象调用的m1方法
m2();
}
}
//6.外部类在方法中,可以创建Inner02对象,然后调用方法即可
Inner02 inner02=new Inner02();
inner02.f1();
}
{//代码块
class Inner03{//局部内部类
}
}
}
3.匿名内部类(重要)
本质还是一个类,他没有名字,他是一个对象,他是一个内部类
1.基本使用
基于接口的匿名内部类
public class Anonymous {
public static void main(String[] args) {
Outer04 outer04=new Outer04();
outer04.method();
}
}
class Outer04{//外部其他类
private int n1=1;
public void method(){
//1.需求:想使用接口A,并创建对象
//2.传统方式:写一个类并创建对象,这个类实现接口和接口方法,对象调用方法
//IA tiger=new Tiger();
//tiger.cry();
//3.需求:tiger/dog类只使用一次,后面不再使用
//4.解决:可以使用匿名内部类简化
//5.triger的编译类型是IA,运行类型是匿名内部类
/*
* 底层 IA tiger=new class XXX implements IA{}
* */
//6.匿名内部类使用一次就没了,triger可以一直使用
IA tiger=new IA(){
public void cry() {
System.out.println("老虎嗷嗷叫");
}
};
tiger.cry();
}
}
interface IA{//接口
public void cry();
}
//class Tiger implements IA{
// @Override
// public void cry() {
// System.out.println("老虎嗷嗷叫");
// }
//}
//class Dog implements IA{
// @Override
// public void cry() {
// System.out.println("小狗哇哇叫");
// }
//}
基于类的匿名内部类:
public class Anonymous02 {
public static void main(String[] args) {
Outer05 outer05=new Outer05();
outer05.method();
}
}
class Outer05{//外部其他类
private int n1=1;
public void method(){
//1.底层:new class Outer05$01 extend Father
//2.编译类型Father,运行类型Outer05$01
//3.底层会直接创建匿名内部类,并返回Outer05$02对象
//4.参数列表会传递给构造器
Father father=new Father("qwq"){//匿名内部类
@Override
public void test() {
System.out.println("重写了text方法");
}
};//有分号,本质还是创建语句
father.test();
//基于抽象类的匿名内部类
Animal animal=new Animal(){
@Override
public void eat() {
System.out.println("吃饭饭");
}
};
animal.eat();
}
}
class Father{//外部其他类
public Father(String name) {
System.out.println(name);
}
public void test(){
}
}
abstract class Animal{
public void eat(){};
}
2.细节
public class AnonymousInnerDetail {
public static void main(String[] args) {
Outer06 outer06 = new Outer06();
outer06.say();
}
}
class Outer06{
private int n1=1;
public void say(){
Student student01=new Student(){
@Override
public void hi() {
System.out.println("hello");
System.out.println(n1);
//只能在方法里面访问外部成员
}
public int n1=10;
};
//1.两种访问方式
//2.可以在匿名内部类的方法里直接访问外部类的所有成员,包括私有
//3.外部其他类不能访问匿名内部类
//4.匿名内部类访问
student01.hi();//动态绑定
//也可以直接调用
new Student(){
@Override
public void hi() {
System.out.println("hello");
}
@Override
public void ok(String s) {
System.out.println(s);
}
}.ok("qwq");
//匿名内部类既是一个对象又是一个类
//上面把他看做一个对象,下面看做一个类
}
}
class Student{
public void hi(){
System.out.println("hi");
}
public void ok(String s){
System.out.println(s);
}
}
//抽象类、接口都可以写匿名内部类
3.应用
(1). 把匿名内部类当作实参直接传递
例1:
public class innerClass01 {
public static void main(String[] args) {
f1(new AA(){
@Override
public void show() {
System.out.println("aaaaa");
}
});//把匿名内部类看做一个参数
//传统方法
f1(new Pic());
}
public static void f1(AA a){//形参是接口类型
a.show();
}
}
interface AA{
void show();
}
//传统方法,还要写一个类;但是使用匿名内部类不用写一个类了
class Pic implements AA{
@Override
public void show() {
System.out.println("bbbbbbb");
}
}
例2;
public class innerClass02 {
public static void main(String[] args) {
Cellphone cellphone= new Cellphone();
cellphone.alarmClock(new Bell() {
//编译类型是Bell,运行类型是xxx$01
//重写了ring方法 Bell bell=new xxx01 extend Bell{ring()}
@Override
public void ring() {
System.out.println("快起床");
}
});
cellphone.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println("上课了");
}
});
}
}
interface Bell{
public void ring();
}
class Cellphone{
public void alarmClock(Bell bell){//形参是接口类型
bell.ring();
}
}
4.成员内部类
1.定义在外部类的成员位置上
2.可以添加任意访问修饰符,因为他是一个成员
3.可以访问外部类的所以成员,包括私有
4.外部类可以创建内部类对象,再调用方法
5.成员内部类访问外部类,直接访问
6.外部其他类访问成员内部类
7.如果成员内部类成员和外部类成员重名,遵守就近原则,访问外部类通过:外部类.this.外部类成员;
public class innerclass03 {
public static void main(String[] args) {
Outer07 outer07 = new Outer07();
outer07.t1();
//3.外部其他类访问成员内部类,2种方式
//方式一:
//new Inner04();
//Outer07.new Inner04();
//这就是一个语法
Outer07.Inner04 inner04=outer07.new Inner04();
//方式二:写一个方法getInner04(),返回一个inner04对象
outer07.getInner04();
}
}
class Outer07{
private int n1=1;
public String name="qwq";
public class Inner04{//成员内部类
//1.可以直接访问外部类的所以成员,包括私有
public void say(){
System.out.println("n1="+n1+"name="+name);
}
}
public Inner04 getInner04(){
return new Inner04();
}
//2.可以在外部类中使用成员内部类
public void t1(){
Inner04 inner04=new Inner04();
inner04.say();
}
}
5. 静态内部类
public class StaticInnerClass {
public static void main(String[] args) {
Outre10 outre10 = new Outre10();
//5.外部其他类访问静态内部类:
//方式一:new Inner10().var
Outre10.Inner10 inner10 = new Outre10.Inner10();
inner10.say();
//方式二:编写一个方法返回静态内部类实例
outre10.get();
//方式三:编写静态方法,通过外部类名访问
Outre10.Inner10 inner101 = Outre10.get();
}
}
class Outre10{
private int n1=10;
private static String name="张三";
//1.放在外部类成员位置,并用static修饰
//2.只能访问外部类的静态成员,包括私有的,非静态的不能访问
//3.作用域为整个外部类
//4.外部类访问静态内部类:先创建内部对象,再访问
static class Inner10{
// public int n1=2;
private static String name="qwq";
public void say(){
System.out.println(Outre10.name);
//6.如果外部类和静态内部类重名,静态内部类访问时遵循
//就近原则,可以通过外部类.外部类成员访问外部类成员
}
}
public static Inner10 get(){
return new Inner10();
}
}
6.练习
s1.a=10//把默认值修改为10
s2.a=5//默认的是5
r.a=5//默认5