static关键字
静态static关键字的特点:
1)随着类的加载而加载
2)优先于对象存在:
它不能和this共存(this:代表当期类对象的地址值引用)
对象还没有new的时候,当前被static修饰的成员就已经内存了
3)被静态修饰
可以被多个对象共享:有共享共用的意思
举例:饮水机中的水(适合) <==> 水杯共享(不适合!)
4)被静态修饰的变量,方法=>静态变量或者静态方法
我们所说的成员变量和成员方法:都指的是非静态
静态的成员的访问方式:类名.变量\类名.方法名()
5)关于static关键字的使用注意事项:
①非静态的方法既可以访问静态变量,也可以访问非静态的变量;既可以调用静态方法,也可以调用非静态方法
②静态的方法:只能访问静态变量;只能调用静态方法
简单记:静态只能访问静态
静态变量和成员变量的区别
所属不同
静态变量属于类,所以也称为为类变量
成员变量属于对象,所以也称为实例变量(对象变量)
内存中位置不同
静态变量存储于方法区的静态区
成员变量存储于堆内存
内存出现时间不同
静态变量随着类的加载而加载,随着类的消失而消失
成员变量随着对象的创建而存在,随着对象的消失而消失
调用不同
静态变量可以通过类名调用,也可以通过对象调用
成员变量只能通过对象名调用
代码块
在Java中,使用{}包裹棋起来的内容,成为代码块!
代码块的分类
局部代码块:在方法定义中使用,作用:限定局部变量的生命周期
构造代码块:在类的成员位置(类中,方法外),使用{}包裹起来作用:给 类中的一些成员进行数据初始化
代码块的特点
每次在执行构造方法之前,如果存在构造代码块,先执行构造代码块中的内容
静态代码块
在类的成员位置,直接使用static{},
特点:
随着类的加载而加载,优先于对象存在!
作用:
也可以通过static代码块,对一些操作 (后期I0流创建文件.JDBC (Java链接数据库注册驱动))
静态代码块就加载一次!
优先级:
静态代码块 > 构造代码块 > 构造方法
eg.
package HemoWork.day10;
public class Test01 {
public static void main(String[] args) {
new Leaf();
}
}
class Root {
static {
System.out.println("Root的静态初始化块");
}
{
System.out.println("Root的普通初始化块");
}
public Root() {
System.out.println("Root的无参数的构造器");
}
}
class Mid extends Root {
static {
System.out.println("Mid的静态初始化块");
}
{
System.out.println("Mid的普通初始化块");
}
public Mid() {
System.out.println("Mid的无参数的构造器");
}
public Mid(String msg) {
this();
System.out.println("Mid的带参数构造器,其参数值:" + msg);
}
}
class Leaf extends Mid {
static {
System.out.println("Leaf的静态初始化块");
}
{
System.out.println("Leaf的普通初始化块");
}
public Leaf() {
super("hello");
System.out.println("Leaf的构造器");
}
}
运行结果:
Root的静态初始化块
Mid的静态初始化块
Leaf的静态初始化块
Root的普通初始化块
Root的无参数的构造器
Mid的普通初始化块
Mid的无参数的构造器
Mid的带参数构造器,其参数值:hello
Leaf的普通初始化块
Leaf的构造器
继承
继承的概念:
将多个类的共性内容抽取到独立的类中,然后这多各类和独立的类产生一种关系:继承关系
继承的好处:
1)提高代码的维护性
2)提高代码的复用性
3)让类和类之间产生了关系,是“多态的前提条件”
什么时候使用继承?
1)不要为了实现部分功能而使用继承关系
2)A is a B的时候可以使用继承
继承的特点:
1)继承只支持单继承,有些语言中支持多继承,但是Java中不支持
2)不支持多继承,但支持多层继承
注意事项:
1)子类继承父类:可以继承父类的非私有的成员,私有的成员外界不能访问,只能在本类中访问。但是可以通过公共访问间接方法
2)构造方法是不能被继承的,但是子类可以简介通过super关键字访问父类的构造方法
成员变量的关系问题:
a)子类继承父类,如果子类中的成员变量名称和父类的成员变量名称不一致,分别访问即可!
b)子类继承父类,如果子类的成员变量名称和父类的成员变量名称致: 如何访问呢?
1)首先在子类的局部位置找,是否存在局部变量名称,如果有,就使用
2)如果没有,就在子类的成员位置找,是否存在这个变量,如果存在,就使用
3)如果在子类的成员位置中没有找到,直接在父类的成员位置中找,如果有,就是使用!
4)如果父类的成员位置都没有,就没有这个变量,报错!
遵循一个原则:就近原则!
继承中无参构造方法的访问:
1)子类继承父类,子类的所有的构造方法都会默认的访问父类的无参方法
2)如果父类中没有无参构造方法子类会怎么样?
子类的所有的构造都会报错! (因为子类所有构造方法默认父类的无参构造方法!)
如何解决呢?
方式1:手动给出父类的无参构造方法(推荐)
方式2:在子类的构造方法中的第一句话:通过super (xxx),间接的访问父类的有参构造方法
方式3:只要子类的所有构造方法中一个能够让父类初始化即可!
方法重载和方法重写的区别:
方法重载:
在一个类中,提供n多个接口,这些功能,方法名相同,参数列表不同,与返回值无关(目的:提高某个功能的扩展性)
参数列表不同:①类型不同,②个数不同,③考虑参数类型的顺序
构造方法也可以重载
方法重写:
在继承关系中,子类出现了和父类一模一样方法声明,重写的目的:子类有自己的功能,需要将父亲的该功能覆盖掉
方法重写时需要注意:
当前子类继承父类时,如果存在方法重写,那么子类重写该方法访问权限不能更低
要么跟父类方法保持一致,要么加上public,最好和父类的修饰一样
什么时候使用继承?、
如果A类是B类的一种,或者B类是A类的一种,这个使用extends完成两者继续关系,体现的是一种"is a"的关系。不要为了部分功能而去使用继承!
eg.
public class People {
private String name;
private int age;
private String sex;
public People() {
}
public People(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public void eat() { }
}
class PeopleNan extends People {
public PeopleNan() {
}
public PeopleNan(String name, int age, String sex) {
super(name, age, sex);
}
@Override
public void eat() {
System.out.println("南方人吃米饭");
}
public String work() {
return "南方人经商";
}
}
class PeopleBei extends People {
public PeopleBei() {
}
public PeopleBei(String name, int age, String sex) {
super(name, age, sex);
}
@Override
public void eat() {
System.out.println("北方人吃面");
}
public String work() {
return "北方人考学";
}
}
class PeopleTest {
public static void main(String[] args) {
People people = new People();
PeopleBei peopleBei = new PeopleBei();
PeopleNan peopleNan = new PeopleNan();
peopleBei.setName("老北");
peopleBei.setAge(40);
peopleBei.setSex("男");
System.out.println("我是" + peopleBei.getName() + ",今年" + peopleBei.getAge() + ",是个" + peopleBei.getSex()+"的");
peopleBei.eat();
System.out.println(peopleBei.work());
peopleNan.setName("南姐");
peopleNan.setAge(40);
peopleNan.setSex("女");
System.out.println("我是" + peopleNan.getName() + ",今年" + peopleNan.getAge() + ",是个" + peopleNan.getSex()+"的");
peopleNan.eat();
System.out.println(peopleNan.work());
}
}
运行结果:
我是老北,今年40,是个男的
北方人吃面
北方人考学
我是南姐,今年40,是个女的
南方人吃米饭
南方人经商
eg2
public class Animal {
private String name;
private int age;
private String color;
public Animal() {}
public Animal(String name, int age, String color) {
this.name = name;
this.age = age;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public void eat(){}
public void play(){}
public void introduce(){
System.out.println("我是一只"+getName()+",我是"+getColor()+"色的,今年"+getAge()+"岁");
}
}
class Cat extends Animal{
public Cat() {}
public Cat(String name, int age, String color) {
super(name, age, color);
}
public void eat(){
System.out.println("猫咪吃饭");
}
public void play(){
System.out.println("猫咪舔自己");
}
public void introduce(){
System.out.println("我是一只"+getName()+"猫,我是"+getColor()+"色的,今年"+getAge()+"岁");
}
}
class Dog extends Animal{
public Dog() {
}
public Dog(String name, int age, String color) {
super(name, age, color);
}
public void eat(){
System.out.println("狗狗吃饭");
}
public void play(){
System.out.println("狗狗吃骨头");
}
public void introduce(){
System.out.println("我是一只"+getName()+"狗,我是"+getColor()+"色的,今年"+getAge()+"岁");
}
}
class AnimalTest{
public static void main(String[] args) {
Animal animal = new Animal();
Cat cat = new Cat("大黄",3,"黄");
Dog dog = new Dog("大毛",5,"白");
cat.eat();
dog.eat();
cat.play();
dog.play();
cat.introduce();
dog.introduce();
}
}
运行结果:
猫咪吃饭
狗狗吃饭
猫咪舔自己
狗狗吃骨头
我是一只大黄猫,我是黄色的,今年3岁
我是一只大毛狗,我是白色的,今年5岁
super和this关键字
this代表本类对应的引用。
super代表父类存储空间的标识(可以理解为父类引用)
final关键字
关于final关键字的特点:
1)可以修饰类,该类不能被继承!
2)可以修饰符成员方法,成员方法不能重写! (根据具体的题意要求!)
3)可以修饰的变量,这个变量此时是一个常量! (自定义常量)
面试题:
final , finally, finalize(的区别?
final的关键字描述以及的三个特点
finally:处理异常用到try… catch… finally(后面讲)
finalize() :跟垃圾回收器有关系:回收内存中没有更多引用的对象(后面在讲常用类)
final修饰的变量:
普通变量:
final int a = 10;
实例变量:
final Student student = new Student();
fina1修饰基本数据类型和引用类型的区别?
final修饰基本数据类型:基本数据类型的对应的数据值不能在被赋值了,只能赋值一次!
final修饰引用类型:引用数据类型对应的地址值不能被改变
final Student s = new Student() ;//修饰实例变量s, s的堆内存地址值永远是固定值!
new Student() ;//重新开辟 空间(报错)
开发中书写常量:
都使用public static final int a = 100 ;
public:访问权限足够大
static:可以被类名直接访问
final:这个变量是一个常虽
多态
多态的概念
一个事物在不同时刻不同形态
多态的前提条件
1)必须存在继承关系extends
2)必须存在方法重写【子类需要覆盖父类的功能】
3)必须有父类引用指向子类对象(向上转型)
F f = new Z();
多态的访问特点
1)针对成员变量的访问问题
编译看左(看Fu类是否存在变量,存在,编译不会报错!)
运行看左(使用Fu类的东西)
2)针对成员方法的访问问题(非静态)
编译看左(看Fu类是否存在这个方法,存在,编译不会报错!)
运行看右(存在方法重写,所以最终子类的功能将父类的该功能进行覆盖!)
3)如果成员方法是静态方法(静态成员方法算不上方法重写,直接可以类名来访问,跟类相关的方法)
编译看左(看Fu类是否存在这个静态方法,存在,编译不会报错!),
运行看左(静态方法:子类出现了父类一模一样的静态方法,不能算重写,和类相关)
4)针对构造方法的访问问题:
存在继承关系:还需要让父类先初始化,然后再子类进行数据初始化!(分层初始化!)
多态的好处
1)提高了代码的复用性(有继承保证)
2)提高了代码的扩展性(有多态保证)
多态的弊端
不能访问子类的特有功能
如何解决?(如何访问子类独有的功能)
方案一:具体的子类创建具体的子类对象
Zi z = new Zi() ;
z.成员方法名()
本身Fu f = new Zi();//已经在堆内存中开辟空间了
Zi z = new Zi();//在堆内存中又开辟空间,从内存角度考虑,这种比较消耗内存空间
方案二:将父类引用转换为子类引用(向下转型)
Fu fu = new Zi();
Zi zi = (Zi)fu;
需要注意:
向下转型使用不当,就出现java. lang. ClassCastException;类转换异常;属于运行时异常。
当前堆内存中的实例不是该类型时,就会出现问题!
eg
class Animal{
static String name = "狗";
int age = 5;
public Animal() {
}
public void eat(){
System.out.println("饿了就吃");
}
}
class Dog1 extends Animal{
String name;
int age = 2;
public Dog1() {
}
public Dog1(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void eat() {
System.out.println("狗吃骨头");
}
public void sleep() {
System.out.println("狗打呼噜");
}
}
public class DuoTaiTest {
public static void main(String[] args) {
Animal animal = new Dog1("大黄");
//成员方法
animal.eat();//子类
//强制类型转换(向下转型)
Dog1 dog2 = (Dog1)animal;
dog2.sleep();
//成员变量
int age = animal .age;
System.out.println(age);//父类
//构造方法
//赋值需要向下转型
System.out.println(((Dog1) animal).getName());
Animal dog = new Dog1("aa");
System.out.println(dog.name);
}
}
运行结果
狗吃骨头
狗打呼噜
5
大黄
狗
eg2
public class JuiceMachineTest {
public static void main(String[] args) {
JuiceMachine juiceMachine = new JuiceMachine();
juiceMachine.makeJuice(new Apple());
juiceMachine.makeJuice(new Banana());
juiceMachine.makeJuice(new Orange());
}
}
class JuiceMachine {
public void makeJuice(Fruit fruit) {
fruit.Juice();
}
}
class Fruit {
public void Juice() {
System.out.println("出汁!");
}
}
class Apple extends Fruit {
public void Juice() {
System.out.println("流出苹果汁");
}
}
class Banana extends Fruit {
public void Juice() {
System.out.println("流出香蕉酱");
}
}
class Orange extends Fruit {
public void Juice() {
System.out.println("流出橙汁");
}
}
运行结果
流出苹果汁
流出香蕉酱
流出橙汁
抽象类
什么是抽象类?
现实世界事物中,某个事物是比较概括性,描述为抽象事物
将某个事务中的一些功能仅仅给出声明即可,没有方法体。
抽象类关键字:abstract关键字
抽象方法的格式:
权限修饰符(eg.pub1ic) abstract 返回值类型方法名 (形式参数列表);
abstract class 类名{}
抽象类的特点:
1)有抽象方法的类一定是抽象类;
2)抽象类中不一定只有抽象方法,还可以有非抽象方法(有方法体) ;
3)抽象类不能实例化=>不能创建对象
通过具体的子类进行实例化(创建对象),抽象类多态Fu fu = new Zi();
4)抽象类的子类有两种情况:
①目前来说:如果抽象类的子类都是抽象类—毫无意义。因为子类也不能new,除非再有具体的子类;
②抽象类的子类是具体类—才能new:抽象 多态的形式Fu fu = new Zi()
抽象类成员的特点:
成员方法:
既可以定义为抽象方法,也可以定义为非抽象方法
成员变量:
既可以定义变量,也可以定义常量
构造方法:
既可以有参狗仔,也可以无参构造
abstract关键字和那些关键字冲突:
final:abstract修饰的类继承后,该类的方法需要重写,而final修饰的类不能继承,也不能有子类,方法更不能重写,相互冲突。
private:私有方法子类的方法不能被继承,就不能被重写,而abstract就是要方法重写。相互冲突。
static:static能被实例化可直接调用,abstract是不能被实例化,相互冲突。
面试题:
一个类中没有抽象方法,那么将这个类定义为抽象类的意义何在?
为了不让它直接实例化!
如何实例化?
1)直接具有具体的子类
2)间接具有具体的子类
可能:某个功能的返回值是它本身---->功能里面的逻辑可能就是在new 最具体的子类!
eg
//创建一个名称为 Vehicle类并将它声明为抽象类,在Vehicle类中声明一个NoOfWheels方法,使它返回一个字符串值.
public abstract class Vehicle {
public abstract String NoOfWheels();
}
//Motorbike类
public class Motorbike extends Vehicle{
@Override
public String NoOfWheels() {
return "双轮车";
}
}
//Car类
public class Car extends Vehicle {
@Override
public String NoOfWheels() {
return "四轮车";
}
}
//创建一个带main方法的类,在该类中创建 Car和Motorbike的实例,
public class VehicleTest {
public static void main(String[] args) {
Vehicle vehicle1 = new Car();
System.out.println(vehicle1.NoOfWheels());
Vehicle vehicle2 = new Motorbike();
System.out.println(vehicle2.NoOfWheels());
}
}
运行结果
四轮车
双轮车
eg.2
public abstract class Animal{
String name;
int age;
String sex;
public Animal() {
}
public Animal(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public abstract void eat();
public abstract void sleep();
public abstract void hobit();
public void introduce(){
System.out.println("我是"+getName()+",我今年"+getAge()+"岁,我是"+getSex()+"的");
}
}
//猫类
public class Cat extends Animal {
public Cat() {
}
public Cat(String name, int age, String sex) {
super(name, age, sex);
}
@Override
public void eat() {
System.out.println("猫吃鱼");
}
@Override
public void sleep() {
System.out.println("猫睡觉");
}
@Override
public void hobit() {
System.out.println("猫玩毛线");
}
}
//狗类
public class Dog extends Animal {
public Dog() {
}
public Dog(String name, int age, String sex) {
super(name, age, sex);
}
@Override
public void eat() {
System.out.println("狗吃饭");
}
@Override
public void sleep() {
System.out.println("狗睡觉");
}
@Override
public void hobit() {
System.out.println("狗打滚");
}
}
//一个测试类
public class AnimalTest {
public static void main(String[] args) {
Animal animal1 = new Dog("大黄",5,"公");
animal1.introduce();
animal1.eat();
animal1.hobit();
animal1.sleep();
Animal animal2 = new Cat("nono",4,"母");
animal2.introduce();
animal2.eat();
animal2.hobit();
animal2.sleep();
}
}
运行结果
我是大黄,我今年5岁,我是公的
狗吃饭
狗打滚
狗睡觉
我是nono,我今年4岁,我是母的
猫吃鱼
猫玩毛线
猫睡觉
接口
本质是体现一个现实世界事物所具有的额外的扩展抽象
接口的特点:
1)不能实例化(不能创建对象)
如何实例化?通过接口的子实现类(一定是具体类)进行实例化----接口多态(使用时最!)
2)子类实现和接口的关系: implements实现关系
3)接口的子类,要么是抽象类,要么重写接口中的所有抽象方法
接口的成员特点:
成员变量:只能常量,默认用public static final修饰
构造方法:接口没有构造方法
成员方法:只有抽象方法,默认用public abstract修饰
抽象类和接口之间的区别:
1)成员的区别
抽象类:
成员变量:既可以是常量,也可以是变量;
成员方法:既可以是抽象方法,也可以是非抽象方法;
构造方法:既存在有参构造,也存在无参构造;
接口:
成员变量:稚嫩是常量,默认修饰符public static final;
成员方法:只能是抽象方法:默认修饰符 public abstract;
构造方法:接口中没有构造方法
2)关系的区别
类与类之间的关系:extends 继承关系
类与接口之间的关系:implements 实现关系
接口与接口之间的关系:extends 继承关系,支持多继承
3)设计理念的区别:
抽象类不能实例化,需要通过具体的子类实例化=>is a
接口不能实例化,需要通过具体的子实现类实例化=>like a
eg.
public class EatingOut {
public static void main(String[] args) {
//创建厨师对象
FoodMenu cooker1 = new ChinaCooker();
FoodMenu cooker2 = new AmricanCooker();
//创建顾客对象
Customer customer = new Customer(cooker1);
//顾客点菜
customer.order();
}
}
//顾客
class Customer {
/*
Cat is a Animal,但凡满足isa的表示都可以设置为继承。
Customer has a FoodMenu,但凡是满足hasa的表示都以属性的形式存在。
*/
private FoodMenu foodMenu;
public Customer() {
}
public Customer(FoodMenu foodMenu) {
this.foodMenu = foodMenu;
}
public FoodMenu getFoodMenu() {
return foodMenu;
}
public void setFoodMenu(FoodMenu foodMenu) {
this.foodMenu = foodMenu;
}
public void order(){
foodMenu.shiZiCchaoJiDan();
foodMenu.yuXiangRouSi();
}
}
//菜单
interface FoodMenu {
void shiZiCchaoJiDan();
void yuXiangRouSi();
}
//中国厨师
class ChinaCooker implements FoodMenu {
@Override
public void shiZiCchaoJiDan() {
System.out.println("中餐厨师做的西红柿炒鸡蛋,得劲!");
}
@Override
public void yuXiangRouSi() {
System.out.println("中餐厨师做的鱼香肉丝,得劲!");
}
}
//外国厨师
class AmricanCooker implements FoodMenu {
@Override
public void shiZiCchaoJiDan() {
System.out.println("西餐厨师做的西红柿炒鸡蛋,蒂丽舍丝");
}
@Override
public void yuXiangRouSi() {
System.out.println("西餐厨师做的鱼香肉丝,蒂丽舍丝");
}
}
运行结果
中餐厨师做的西红柿炒鸡蛋,得劲!
中餐厨师做的鱼香肉丝,得劲!
类型与类型之间的关系
is a(继承)、has a(关联)、like a(实现)
is a:
Cat is a Animal(猫是一个动物)
凡是能够满足is a的表示“继承关系”
A extends B
has a:
I has a Pen(我有一支笔)
凡是能够满足has a关系的表示“关联关系”
关联关系通常以“属性”的形式存在。
like a:
Cooker like a FoodMenu(厨师像一个菜单一样)
凡是能够满足like a关系的表示“实现关系”
实现关系通常是:类实现接口。
形式参数和返回值问题
如果方法的形式参数是类调用方法的时候,如何传递实际参数?
具体类,调用该方法,实际参数需要传递当前具体类的对象
抽象类,调用该方法实际参数需要传递的抽象类的子类对象 (抽象类多态)
接口 调用该方式,实际参数需要传递的是当前接口的子实现类对象(接口多态)
如果一个方法的返回值是引用类型,最终方法结束,如何返回?
具体类 :方法返回的就是当前具体类对象!
抽象类 :需要返回的是抽象类的子类对象
接口:需要返回的是该接口的子实现类对象
包
编译和运行
同一个包下的编译和运行:
第一种方式(手动方式)
1)需要在当前文件夹下将com文件夹以及子文件夹qf手动创建出来
2)进入dos控制台:进入当前java文件所处的目录下
javac 源文件名称(HelloWorld.java)---->HelloWorld.class 字节码文件
3)将2)步产生的字节码文件放在1)qf子文件夹下
4)运行:带上包运行 :java 包名.类名
java com.qf.HelloWorld
第二种方式(自动方式)
1)直接进入dos控制台,进入到指定目录下:
javac -d . java源文件(HelloWorld.java)
2)自动将包名创建出来以及包下面的字节码文件
3)运行:带上包运行 :java 包名.类名
java com.qf.HelloWorld
不同包下的编译和运行
1)将net.hsbc.Demo类导入进来
2)通过自动方式将net.hsbc.Demo---->先编译成
3)然后再通过自动方式对Test.java文件进行编译
4)运行即可java com.qf.Test
package
第一:package出现在java源文件第一行。
第二:带有包名怎么编译?javac -d . xxx.java
第三:怎么运行?java 完整类名
补充:以后说类名的时候,如果带着包名描述,表示完整类名。
如果没有带包,描述的话,表示简类名。
import
import什么时候不需要?
java.lang不需要。
同包下不需要。
其它一律都需要。
eg
import 完整类名;
import 包名.*;
import java.util.Scanner; // 完整类名。
// 同学的疑问:这样是不是效率比较低。
// 这个效率不低,因为编译器在编译的时候,会自动把*变成具体的类名。
import java.util.*;
// 想省懒劲你不能太省了。
import java.*; 这是不允许的,因为在java语言中规定,这里的*只代表某些类的名
访问控制权限
访问控制权限都有哪些?
private | 私有 |
---|---|
public | 公开 |
默认 | |
protected | 受保护 |
以上的4个访问控制权限:控制的范围是什么?
private表示私有的,只能在本类中访问
public表示公开的,在任何位置都可以访问
"默认"表示只能在本类,以及同包下访问
protected表示只能在本类、同包、子类中访问.
访问控制修饰符 | 本类 | 同包 | 子类 | 任务位置 |
---|---|---|---|---|
public | 可以 | 可以 | 可以 | 可以 |
protected | 可以 | 可以 | 可以 | 不行 |
默认 | 可以 | 可以 | 不行 | 不行 |
private | 可以 | 不行 | 不行 | 不行 |
内部类
格式
内部类:
在一个类中可以定义另一个:
在类A 中定义了类B,将类B就称为类A的内部类,类A就是外部类!
成员内部类:
在一个类的成员位置中定义了另一个类
内部类可以访问外部类的成员,包括私有!
//外部类
class Outer{
//成员变量
public int num = 100 ;
private int num2 = 200 ;
class Inner{ //成员内部类
//成员内部类的一个成员方法
public void method(){
System.out.println("method Inner");
System.out.println();
System.out.println(num2);
}
}
//外部类的成员方法
public void show(){
//访问的成员内部类的method--->通过创建内部类对象来访问
//method() ;错误的----访问的本类的method方法
Inner inner = new Inner() ;
inner.method();
}
}
//测试
public class InnerClassDemo {
public static void main(String[] args) {
//创建外部类对象
Outer outer = new Outer() ;
outer.show();
}
}
外部类访问内部类
1)外部类如何直接访问内部类的成员方法?
格式:
外部类名.内部类名 对象名 = new 外部类对象().new 内部类对象() ;
class Outer2{
private int num = 20 ;
//成员内部类
class Inner2{
public void show(){
System.out.println(num);
}
}
//外部类的成员方法
public void method(){
// 创建内部类对象访问内部类的成员方法
}
}
//测试类
public class InnerClassDemo2 {
public static void main(String[] args) {
//外部类名.内部类名 对象名 = 外部类对象.内部类对象;
//适用于:通过外部类直接访问成员内部类的成员(前提条件:当前成员内部类是一个非静态类)
Outer2.Inner2 oi = new Outer2().new Inner2() ;
oi.show() ;
}
}
2)关于我们成员内部类的修饰符:
在成员内部类上面—加入private修饰:为了数据的安全性,它的访问—就要外部类的公共访问间接访问…
非static内部类不能有static修饰的变量或方法
非static的内部类,在外部类加载的时候,并不会加载它,所以它里面不能有静态变量或者静态方法。
1、static类型的属性和方法,在类加载的时候就会存在于内存中。
2、要使用某个类的static属性或者方法,那么这个类必须要加载到jvm中。
伪代码
举例:
人首先身体---身体内有心脏
class Body{
//内部类:心脏
private class Heart{ //加入private:保证数据的安全性
//手术
public void operator(){
System.out.println("心脏搭桥手术....") ;
}
}
//外部类提供一些公共访问
public void method(){
if("如果你是外科医生"){
Heart heart = new Heart() ;
heart.operator() ;
}
}
}
//外部类直接访问成员内部类的成员
3)如果当前成员内部类是静态的, 里面的方法无论是静态的还是非静态的,都只能访问外部类的静态成员,包括私有!
如何直接访问静态成员内部类的成员呢?
将静态的成员内部类看成是外部类的静态成员访问
直接访问方式
外部类名.内部类名 对象名 = new 外部类名.内部类名() ;
class Outer3{
//定义非静态的成员变量
public int num = 50 ;
private static int num2 = 20 ;
//定义成员内部类:静态的 ---->静态的成员内部类可以看成是外部类的静态成员
static class Inner3{//此时类都是静态
public void show(){
// System.out.println(num);
System.out.println(num2);
}
public static void show2(){
// System.out.println(num);
System.out.println(num2);
}
}
}
//测试类
public class InnerClassDemo3 {
public static void main(String[] args) {
// 外部类名.内部类名 对象名 = 外部类对象.内部类对象;
//Outer3.Inner3 oi = new Outer3().new Inner3() ; 适用不了了
// 外部类名.内部类名 对象名 = new 外部类名.内部类名() ;
Outer3.Inner3 oi = new Outer3.Inner3() ;
oi.show();
oi.show2() ; //静态---不推荐对象名访问
System.out.println("------------------------------");
//show2()的另一种方式
Outer3.Inner3.show2(); //show2()静态方法
}
}