文章目录
类的封装
package class_and_object;
public class Cook {
String name;
public Cook() {
name = "Jack Chen";
}
void cutPepper() {
System.out.println(name + "切辣椒");
}
void washVegetables() {
System.out.println(name + "洗蔬菜");
}
void cooking(String dish) {
washVegetables();
cutPepper();
System.out.println(name + "开始烹饪" + dish);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Cook jack = new Cook();
System.out.println("***请让厨师为我做一份香辣肉丝***");
jack.cooking("香辣肉丝");
System.out.println("***请问厨师叫什么名字***");
System.out.println(jack.name);
System.out.println("***请让厨师为我切一份辣椒***");
jack.cutPepper();
}
}
package class_and_object;
public class Cook {
String name;
public Cook() {
name = "Jack Chen";
}
void cutPepper() {
System.out.println(name + "切辣椒");
}
void washVegetables() {
System.out.println(name + "洗蔬菜");
}
void cooking(String dish) {
washVegetables();
cutPepper();
System.out.println(name + "开始烹饪" + dish);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Cook jack = new Cook();
System.out.println("***请让厨师为我做一份香辣肉丝***");
jack.cooking("香辣肉丝");
System.out.println("***请问厨师叫什么名字***");
System.out.println(jack.name);
System.out.println("***请让厨师为我切一份辣椒***");
jack.cutPepper();
}
}
package class_and_object;
public class Waiter {
Cook jack = new Cook();
void takeOrder(String dish) {
jack.cooking(dish);
System.out.println("您的菜做好了,请慢用");
}
void saySorry() {
System.out.println("抱歉,餐厅不提供此项服务");
}
}
package class_and_object;
public class Waiter_Customer {
public static void main(String[] args) {
Waiter tom = new Waiter();
System.out.println("***请让厨师为我做一份香辣肉丝***");
tom.takeOrder("香辣肉丝");
System.out.println("***请问厨师叫什么名字***");
tom.saySorry();
System.out.println("***请让厨师为我切一份辣椒***");
tom.saySorry();
}
}
类的继承
1、extends关键字
package class_and_object;
public class Computer { //父类:电脑
String screen = "液晶显示屏";
void startUp() {
System.out.println("电脑正在开机,请稍等...");
}
}
package class_and_object;
public class Pad extends Computer{ //子类:平板电脑
String battery = "5000毫安电池";
void open3G() {
System.out.println("打开3G网络");
}
}
package class_and_object;
public class Computer_Pad {
public static void main(String[] args) {
Computer com = new Computer();
Pad ipad = new Pad();
System.out.println(com.screen);
com.startUp();
System.out.println(ipad.screen);
ipad.startUp();
System.out.println(ipad.battery);
ipad.open3G();
}
}
说明子类可以直接调用从父类那里继承过来的属性和行为
2、方法的重写override
子类与父类完成同一件事,但是它们完成的方法完全不同
package class_and_object;
public class Computer { //父类:电脑
String screen = "液晶显示屏";
void startUp() {
System.out.println("电脑正在开机,请稍等...");
}
void showPicture() {
System.out.println("台式机电脑:用鼠标点击");
}
}
package class_and_object;
public class Pad extends Computer{ //子类:平板电脑
String battery = "5000毫安电池";
void open3G() {
System.out.println("打开3G网络");
}
void showPicture() {
System.out.println("平板电脑:用手指点击触摸屏");
}
}
package class_and_object;
public class Computer_Pad {
public static void main(String[] args) {
Computer com = new Computer();
Pad ipad = new Pad();
com.showPicture();
ipad.showPicture();
}
}
3、super关键字
super()关键字的三种用法:调用父类的构造方法、调用父类的属性、调用父类的成员方法
this关键字代表本类对象,super关键字代表父类对象
这个super()也可以调用父类的构造方法,语法同this关键字,同样需要注意的是,我这个构造方法之前不能再写其他的初始化方法
package class_and_object;
public class Computer { //父类:电脑
String screen = "液晶显示屏";
void startUp() {
System.out.println("电脑正在开机,请稍等...");
}
void showPicture() {
System.out.println("台式机电脑:用鼠标点击");
}
String sayHello() {
return "欢迎使用";
}
}
package class_and_object;
public class Pad extends Computer{ //子类:平板电脑
String battery = "5000毫安电池";
public Pad(){
super(); //super()必须在最前面
this.screen = super.screen;
}
void open3G() {
System.out.println("打开3G网络");
}
void showPicture() {
System.out.println("平板电脑:用手指点击触摸屏");
}
String sayHello() {
// return "欢迎使用" + "平板电脑";
return super.sayHello() + "平板电脑";
}
}
package class_and_object;
public class Computer_Pad {
public static void main(String[] args) {
Computer com = new Computer();
Pad ipad = new Pad();
System.out.println(com.sayHello());
System.out.println(ipad.sayHello());
}
}
4、注意事项
多重继承
假如我一个子类又想继承parent1的属性和方法,又想继承parent2的属性和方法,如何解决:多重继承
package class_and_object;
class Parent2{
void show(){
System.out.println("我是最顶层的父类");
}
}
class Parent1 extends Parent2{
}
class Child extends Parent1{
}
public class Multiple_inheritance {
public static void main(String[] args) {
// 多重继承
Child child = new Child();
child.show();
}
}
子类覆盖父类的属性
子类覆盖了父类的属性,子类有一个与父类同名的属性,虽然这俩的名字相同,但是我这么写出来的话, 那就是属于我子类独有的属性
package class_and_object;
class Parent{
String name;
public Parent(String name){
this.name = name;
}
}
class Child1 extends Parent{
String name = "Jack"; //虽然与父类的属性同名,但仍然属于子类 独有的属性
public Child1(String name) {
super(name);
}
}
public class Property_with_the_same_name {
public static void main(String[] args) {
// 父类 与 子类 有相同名字的属性
Child1 child = new Child1("tom");
System.out.println(child.name);
}
}
这两个类里的name就完全不是一个东西
object类
在java中,所有的类都会直接或间接地继承object这个类,object类是一个特殊的类,它是所有类的父类,是java中最基层的类
所有类的超级父类 ,就是这个object类
getClass()方法
因为object是所有类的父类,所以object数组可以存放任何一个类的对象
用for each循环输出obj的getClass方法,返回对象执行时的Class实例,即我这个类的全名
package class_and_object;
public class GetClass {
public static void main(String[] args) {
// 用for each循环输出obj的getClass方法,返回对象执行时的Class实例,即我这个类的全名
Object arr[] = new Object[4];
arr[0] = new Object();
arr[1] = new String("字符串");
arr[2] = new Integer(10);
arr[3] = new GetClass();
for(Object obj: arr) {
System.out.println(obj.getClass());
}
}
}
toString()方法
package class_and_object;
public class GetClass {
public static void main(String[] args) {
Object arr[] = new Object[4];
arr[0] = new Object();
arr[1] = new String("字符串");
arr[2] = new Integer(10);
arr[3] = new GetClass();
for(Object obj: arr) {
System.out.println(obj.toString());
}
}
}
第一个它返回的是一个默认值:类名+@+16进制的哈希值
第二个它返回字符串的字面值,因为String这个类重写了这个方法
package class_and_object;
public class GetClass {
public static void main(String[] args) {
Object arr[] = new Object[4];
arr[0] = new Object();
arr[1] = new String("字符串");
arr[2] = new Integer(10);
arr[3] = new GetClass();
for(Object obj: arr) {
System.out.println(obj.toString());
System.out.println(obj);
}
}
@Override
public String toString() {
return "我是GetClass类";
}
}
其中,由以上两种情况可见,在System.out中,这个toString是可以删掉的,如果我们直接输出这个对象的话,则会自动调用它的toString方法
equals()方法
这个默认的object类的 equals方法, 其实比较的是两个对象的地址是否相等
package class_and_object;
public class GetClass {
public static void main(String[] args) {
// 用for each循环输出obj的getClass方法,返回对象执行时的Class实例,即我这个类的全名
Object arr[] = new Object[4];
arr[0] = new Object();
arr[1] = new String("字符串");
arr[2] = new Integer(9);
arr[3] = new GetClass();
System.out.println(arr[0].equals(arr[3])); //false
arr[3] = arr[0];
System.out.println(arr[0].equals(arr[3])); //true
arr[3] = new Object();
System.out.println(arr[0].equals(arr[3])); //false
}
@Override
public String toString() {
return "我是GetClass类";
}
}
我们通过重写equals方法,就可以自定义地编写我们对象之间的比较规则
在计算机中,(两个对象之间)它默认比较的是计算机的内存地址
package class_and_object;
public class Person {
String name;
String id;
@Override
public boolean equals(Object obj) {
Person p = (Person) obj;
boolean b1 = this.name.equals(p.name);
boolean b2 = this.id.equals(p.id);
return b1 && b2;
}
}
package class_and_object;
public class Object_equals {
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person();
Person p3 = new Person();
Person p4 = new Person();
p1.name = "小明";
p1.id = "123";
p2.name = "小红";
p2.id = "123";
p3.name = "小明";
p3.id = "456";
p4.name = "小明";
p4.id = "123";
System.out.println(p1.equals(p2));
System.out.println(p1.equals(p3));
System.out.println(p2.equals(p3));
System.out.println(p1.equals(p4));
System.out.println(p1 == p4); //在计算机中,它默认比较的是计算机的内存地址
}
}
方法的重载(overload)
方法的重载属于类的多态性的内容之一
package class_and_object;
public class Method_Overload {
static int add(int a) { //最普通的方法
return a;
}
static double add(double b) { //参数类型不同
return b;
}
// 如果int add(int a, int b)不存在的话,java无法区分add(int a, double b)和add(double b, int a)该调用哪一个
static int add(int a, int b) { //定义与第一个方法参数个数不同
return a + b;
}
static int add(int a, double b) { //参数类型不同
return (int)(100);
}
static int add(double b, int a) { //参数类型不同
return (int)(-100);
}
public static void main(String[] args) {
System.out.println("调用add(int a)方法:" + add(1));
System.out.println("调用add(double b)方法:" + add(1.1));
System.out.println("调用add(int a, int b)方法:" + add(1, 2));
System.out.println("调用add(int a, double b)方法:" + add(1, 2.1));
System.out.println("调用add(double b, int a)方法:" + add(1.1, 2));
}
}
类的上下转型
上:转型方法
子类的对象一定是父类的对象,但是父类的对象不一定是子类的对象了
子类的对象转为父类的对象,就是向上转型;父类的对象转为子类的对象,就是向下转型
package class_and_object;
public class Person {
public Person(String name) {
System.out.println("您好,我叫" + name);
}
}
package class_and_object;
public class Student extends Person{
public Student(String name) {
super(name);
}
public static void main(String[] args) {
Person p1 = new Person("tom");
Person p2 = new Student("jerry");
}
}
父类对象 强制转换为 子类对象,这个就是向下转型,向下转型存在一定风险
package class_and_object;
public class Person {
public Person(String name) {
System.out.println("您好,我叫" + name);
}
}
package class_and_object;
public class Doctor extends Person{
public Doctor(String name) {
super(name);
}
}
package class_and_object;
public class Student extends Person{
public Student(String name) {
super(name);
}
public static void main(String[] args) {
//向上转型 都是正确的
Person p1 = new Person("tom");
Person p2 = new Student("jerry");
Person p3 = new Doctor("jack");
// Doctor dr1 = (Doctor)p1; //向下转型错误
// Doctor dr2 = (Doctor)p2; //向下转型错误
Doctor dr3 = (Doctor)p3; //这个向下转型 是正确的
}
}
下:instanceof关键字
通过上例,我们发现,只有当过医生的人才可以强制转换成医生的对象,而其他人则不可以
我们有没有什么方法 来判断这个人是否可以当医生呢?
instanceof关键字:判断某一个对象是否继承自某一个类
package class_and_object;
public class Computer_instanceof { //父类:电脑类
public static void main(String[] args) {
PPad ipad = new PPad();
LenovoPad lenovopad = new LenovoPad();
Person per = new Person("tom");
System.out.println("Pad是否继承自电脑? " + (ipad instanceof Computer_instanceof));
System.out.println("lenovopad是否继承自PPad? " + (lenovopad instanceof PPad));
System.out.println("lenovopad是否继承自电脑? " + (lenovopad instanceof Computer_instanceof));
System.out.println("ipad是否继承自LenovoPad? " + (ipad instanceof LenovoPad));
System.out.println("ipad是否继承自Object? " + (ipad instanceof Object));
// System.out.println("per是否继承自PPad? " + (per instanceof PPad));
}
}
class PPad extends Computer_instanceof{ //平板电脑类
}
class LenovoPad extends PPad{ //联想平板电脑类
}
说明这个instanceof关键字: 他可以判断我是否能继承自父类的父类,就是我的超级父类也可以这么判断,甚至这里可以写Object(所有类的父类)
**反例:**直接报错,因为我这个Pad类和Person类 没有任何继承关系,两个没有任何继承关系的类是不能用instanceof关键字 进行比较的
抽象类
上:抽象类和抽象方法
像颜色这种没有人能说清他长什么样子的,他究竟是什么的类,我们就称它为抽象类
在java中,用abstract这个关键字来对它进行修饰
package class_and_object;
public abstract class Color {
public void show() {
}
}
class Red extends Color {
public void show() {
System.out.println("我是红色");
}
}
class Blue extends Color {
public void show() {
System.out.println("我是蓝色");
}
}
package class_and_object;
public class Color_Test {
public static void main(String[] args) {
Color c1 = new Red();
Color c2 = new Blue();
c1.show();
c2.show();
// Color c3 = new Color(); //不能创建抽象类的对象
}
}
不能创建抽象类的对象。既然它是一个抽象类的对象,那么它就不能进行实例化。若想创建抽象类的对象,必须用它的子类进行实例化
在抽象类中,有一种方法叫做抽象方法,这种方法是只需声明不需实现的
package class_and_object;
public abstract class Teacher { //抽象类
abstract public void teaching(); //抽象方法
}
class MathTeacher extends Teacher{
@Override
public void teaching() { //前面有一个小三角,说明它在实现上面的抽象方法
System.out.println("这节课我们来讲一下三角函数");
}
}
class EnglishTeacher extends Teacher{
@Override
public void teaching() { //前面有一个小三角,说明它在实现上面的抽象方法
System.out.println("open the book");
}
}
package class_and_object;
public class Teacher_Test {
public static void main(String[] args) {
Teacher lee = new MathTeacher();
Teacher tom = new EnglishTeacher();
lee.teaching();
tom.teaching();
}
}
在父类老师里,成员方法里什么都没写,但是数学老师和英语老师都继承了老师类,我并没有重写它这个teaching方法,这就导致了我这个数学老师和英语老师也什么都没讲,那这样这个类创建了有什么意义呢
为了避免这样的问题,就出现了抽象方法,用abstract来修饰。这种方法只需声明,不需实现;并且含有抽象方法的类必须是抽象类
上面的例子体现出,这种抽象类必须被继承(不然他就不能被实例化),而这个抽象类里的抽象方法则必须被抽象类的子类所重写(实现)
因为抽象方法没有具体实现,所以每一个子类都必须实现这个抽象方法
下:抽象类实例
package class_and_object;
public abstract class Animal { //动物类
public Animal(){
System.out.println("创建了一个动物");
}
public abstract void eat(); //抽象类中的 抽象方法 只需声明,无需实现
abstract public void reproduce();
}
package class_and_object;
public abstract class Bird extends Animal{
String feather; //羽毛
public Bird(String feather) {
System.out.println("创建了一个鸟类");
this.feather = feather;
}
public void growFeather() { //还有自己最普通的 成员方法(函数)
System.out.println("长满" + feather + "羽毛");
}
abstract public void move(); //这个抽象类里 也有它自己的抽象方法
public void reproduce() { //前面的小三角表明 这是在实现父类中的抽象方法
System.out.println("下蛋");
}
}
package class_and_object;
public class Seagull extends Bird{
public Seagull(String feather) {
super(feather);
System.out.println("我是一只海鸥");
}
@Override
public void move() {
System.out.println("海鸥飞翔");
}
@Override
public void eat() {
System.out.println("海鸥吃鱼");
}
public static void main(String[] args) {
Seagull jack = new Seagull("白色");
jack.eat();
jack.move();
jack.growFeather();
jack.reproduce();
}
}
package class_and_object;
public class Chicken extends Bird{
public Chicken(String feather) {
super(feather);
System.out.println("我是一只小鸡");
}
@Override
public void move() {
System.out.println("小鸡快跑");
}
@Override
public void eat() {
System.out.println("小鸡吃米");
}
public static void main(String[] args) {
Chicken duoduo = new Chicken("黄色");
duoduo.eat();
duoduo.move();
duoduo.growFeather();
duoduo.reproduce();
}
}
我一个子类继承了抽象类之后,需要实现这个抽象类以及它父类的所有的抽象方法,所以本题弹出了两个需要重写(实现)的抽象方法
因为我这个父类Bird类有有参数的构造方法,所以我要在这里补充一个构造方法
我一个子类实现了父类的所有抽象方法,而且我这个抽象类鸟类也可以实现父类的抽象方法
本题中,用了三层继承关系,小鸡继承了鸟类,鸟类继承了动物类。动物类提供了两个抽象方法,一个是吃一个是繁殖。鸟类提供了一个抽象方法:就是移动move,同时它还提供了一个非抽象方法,还实现了一个父类的抽象方法
接口
假如我有这样的需求:我三角形这个类不需要draw方法,那我们就必须把图形类的这个draw方法删掉。但这个方法是一个抽象方法,如果将它删掉,我们就会发现其他子类的draw方法同时消失了
但是我的四边形类和N边形类需要这个方法,怎么办呢?
只能将这个方法写成子类独有的方法,这样的话就不利于我们对这个程序做架构,不利于设计这个程序
于是我们引进接口的概念:我们将这个draw方法写到接口中,然后让四边形和N边形这个类来实现这个接口,三角形则不实现。当四边形和N边形实现这个接口的时候,我们就必须将这个draw方法实现
package class_and_object;
public interface DrawInterface{
public void draw();
}
package class_and_object;
public class Qua implements DrawInterface{ //四边形简称,四边形类 实现DrawInterface接口
@Override
public void draw() {
System.out.println("绘制四边形");
}
}
package class_and_object;
public class Square implements DrawInterface{ //正方形类 实现DrawInterface接口
@Override
public void draw() {
System.out.println("绘制正方形");
}
public static void main(String[] args) {
DrawInterface d1 = new Qua(); //接口也支持类的向上向下转型
d1.draw(); //直接创建接口的对象,然后用它的一个实现类 对它进行实例化
DrawInterface d2 = new Square();
d2.draw();
}
}
接口也支持类的向上向下转型,所以我们这里可以直接创建接口的对象,然后用它的一个实现类 对它进行实例化
我们可以看到,这两个类Qua类和Square类根本没有继承的关系,但是它们同时实现了同一个抽象方法,并不是用抽象类来对它俩进行控制,所以接口用起来很方便
接口的多重继承
与抽象类相比,接口最大的优势就是它能够实现多重继承
接口的多重继承从两方面体现:接口继承接口 和 类实现接口
一个类只能继承一个父类,但是接口不一样,一个类可以实现多个接口
类实现接口(一个类可以实现多个接口)
package multiple_inheritance;
public interface Attack {
public void shoot();
}
package multiple_inheritance;
public interface Treatment {
public void treat();
}
package multiple_inheritance;
public class Infantry implements Attack{
@Override
public void shoot() {
System.out.println("步兵进行攻击");
}
}
package multiple_inheritance;
public class Medic implements Attack, Treatment{
@Override
public void treat() {
System.out.println("医务兵治疗他人");
}
@Override
public void shoot() {
System.out.println("医务兵攻击");
}
}
package multiple_inheritance;
public class Demo {
public static void main(String[] args) {
Infantry tom = new Infantry();
tom.shoot();
Medic lily = new Medic();
lily.shoot();
lily.treat();
}
}
接口继承接口
package multiple_inheritance;
public interface Attack {
public void shoot();
}
package multiple_inheritance;
public interface Treatment extends Attack{
public void treat();
}
package multiple_inheritance;
public class Infantry implements Attack{
@Override
public void shoot() {
System.out.println("步兵进行攻击");
}
}
package multiple_inheritance;
public class Medic implements Treatment{
@Override
public void shoot() {
System.out.println("医务兵攻击");
}
@Override
public void treat() {
System.out.println("医务兵治疗他人");
}
}
package multiple_inheritance;
public class Demo {
public static void main(String[] args) {
Infantry tom = new Infantry();
tom.shoot();
Medic lily = new Medic();
lily.shoot();
lily.treat();
}
}
接口与抽象类的对比
抽象类和接口都包含了可以由子类 继承实现 的成员,两者有何区别?
在接口中,只能声明抽象方法。但是接口可以把abstract关键字省略,默认它也是抽象方法
而在抽象类中,加上abstract关键字就是抽象方法,不加就是非抽象方法(因为抽象类可以有非抽象方法)
接口会默认给成员变量添上两个关键字:final static,也就是说,这是一个静态常量,所以不可更改它的值
另外,我可以直接调用interface.id(接口中的静态常量)***
而抽象类中的成员变量可以是 任意类型*(static、final…)
在抽象类中,创建静态代码块和静态方法,它是能够被执行的
(虽然抽象类不能实例化对象,但是他这个静态方法是可用的)
而在接口中,创建静态代码块或者静态方法都会报错,这种语法在接口中不允许出现
package comparision_of_interface_and_abstract_class;
public abstract class Parent1 {
public Parent1() {
System.out.println("我们创造了一个抽象类");
}
String name = "tom"; //成员变量可以是任意类型
static public void show() { //抽象类中可以有静态方法或静态代码块
System.out.println("这是抽象类的静态方法");
}
}
package comparision_of_interface_and_abstract_class;
public interface Interface1 {
int id = 123; //接口中的成员变量 只能是 静态常量
public void action(); //接口中的方法 只能是 抽象方法
}
package comparision_of_interface_and_abstract_class;
public interface Interface2 {
}
package comparision_of_interface_and_abstract_class;
public class Demo extends Parent1 implements Interface1, Interface2{
public static void main(String[] args) {
Demo d = new Demo();
d.name = "jack";
System.out.println(d.name);
Parent1.show();
}
@Override
public void action() {
}
}
java类包
java中的类包有这样一个功能:它相当于一个小容器,我们将一些类放到这个容器中,方便对这些类进行归类整理
在java中,如果我们想要调用一个包中的类,就会用到这样的语法:(这是一个类的完整名称)
我们不能调用两个包下的同名类,因为这样会分不清我在psvm里创建的类是属于哪个包下的(也可以在创建类的时候 使用完整类名)
既然java提供了很多包,我们也可以自己来添加包
创建包的命名规则:名字得倒过来写(例如:com.mingri)
package com.mingri;
public class Action {
public void show() {
System.out.println("上天");
}
}
package default_package;
public class Action {
public void show() {
System.out.println("入地");
}
}
package default_package;
//import java.sql.Date; //一定不能调用两个包下的 同名类
//import java.util.*;
//import java.util.ArrayList;
//import java.util.Date;
//import java.util.List;
//import java.util.*;
public class Demo {
public static void main(String[] args) {
// Date date = new Date();
// List list = new ArrayList();
// Date date = new Date(1111);
Action a = new Action();
a.show();
com.mingri.Action b = new com.mingri.Action();
b.show();
}
}
我如果直接导入com.mingri包的话,那我创建对象show()出来的结果就是上天
这就是java类包的效果
它不仅可以将我们的程序分出层次结构(比如不同的类放在不同的包里),它还可以将同名的类进行区分(使用完整的类名就可以区分所有同名类),虽然两个类都叫action,但是创建出来的对象是完全不同的
访问控制
protected:是希望由子类来继承的,其他的和我在同一个包下的类 也能调用
default:控制了只有和我在同一个包内的人 才能使用
private:谁都不许用
package parent;
public class Parent {
public void show() {
System.out.println("Parent向您致敬");
}
}
package parent;
public class Child extends Parent{
public void show() {
super.show();
}
}
package demo;
import parent.Parent;
public class Demo {
public static void main(String[] args) {
Parent p = new Parent();
p.show();
}
}
package parent;
public class Parent {
protected void show() { //受保护
System.out.println("Parent向您致敬");
}
}
package parent;
public class Child extends Parent{
public void show() {
super.show();
}
}
package demo;
import parent.Child;
import parent.Parent;
public class Demo {
public static void main(String[] args) {
Parent p = new Parent();
// p.show(); //将Parent类改成protected权限 对其它包中的非子类 不可见 所以会报错
Child c = new Child();
c.show(); //将Parent类改成protected权限 对本类所在的包 是可见的
}
}
package parent;
public class Parent {
protected void show() { //受保护
System.out.println("Parent向您致敬");
}
}
package child;
import parent.Parent;
public class Child extends Parent{
public void show() {
super.show();
}
}
package demo;
import child.Child;
import parent.Parent;
public class Demo {
public static void main(String[] args) {
Parent p = new Parent();
// p.show(); //将Parent类改成protected权限 对其它包中的非子类 不可见 所以会报错
Child c = new Child();
c.show(); //将Parent类改成protected权限 对本类所在的包 是可见的
}
}
即使我这个子类和我不在同一个包下,因为protected权限对其他包中的子类也是可见的
package parent;
public class Parent {
void show() { //缺省
System.out.println("Parent向您致敬");
}
}
package child;
import parent.Parent;
public class Child extends Parent{
public void show() {
super.show(); //缺省时(这句语句是错误的),其他包中的 子类就访问不到了,不管你和我什么关系,只要我们不在同一个包下,你就不能用我
}
}
package parent;
public class Parent {
private void show() { //私有 只能在本类中使用
System.out.println("Parent向您致敬");
}
}
package parent;
public class Child extends Parent{
public void show() {
// super.show();
}
}
我们发现,即使在同一个包下,你也是我的子类,但是这个show方法仍然不允许你使用
私有方法只有我自己(本类中)可以用
final关键字
这节介绍final关键字***对类的继承的一些 控制的作用***
用到final关键字有三个场景
final类
被final修饰过的类有一个特点:它不允许有子类(即它不能被继承)
在java中,String类和System类就是不允许有子类的
final方法
final常量
加了final关键字后,这个常量的值就不能再被修改了
内部类
成员内部类
外部类不能直接调用成员内部类的成员方法,如果要调用这个方法的话,我们要先创建一个内部类的对象。
这就是外部类方法去调用内部类方法
在main方法中如何创建成员内部类:Demo.innerClass in = d.new innerClass();
package inner_class;
public class Demo {
innerClass in = new innerClass();
public void outf() {
in.inf();
}
class innerClass{ //成员内部类
int y = 0;
public innerClass() {
}
public void inf() {
System.out.println("内部类方法y = " + y);
}
}
public static void main(String[] args) {
Demo d = new Demo();
d.outf();
Demo.innerClass in = d.new innerClass();//在main方法中 这样创建 成员内部类 的对象
in.inf();
}
}
局部内部类
我希望我这个s能使用方法中的参数,那如何创建这个内部类的对象呢?
将innerClass2这个类返回,这是会报错的,(因为这个类是在方法体之内声明的,若把这个类返回出去的话,在方法体之外是不存在这个类的)如何解决这个问题?
使用接口来解决这个问题
接口OutInterface专门用来给这个内部类做一个向上转型
我们看到,即使我在构造方法中给它添加了一个值,但是我们获取到的是方法之外的参数x,将这个值传给了s
package inner_class;
public class Demo2 {
public OutInterface action(String x) {
class innerClass2 implements OutInterface{ //局部内部类
public innerClass2(String s) {
s = x;
System.out.println(s);
}
}
return new innerClass2("do");
}
public static void main(String[] args) {
Demo2 d = new Demo2();
d.action("局部内部类");
}
}
interface OutInterface{
}
匿名内部类
我们没有创建任何对象,那就直接return new一个接口OutInterface2(),但是这个接口并不是一个具体的类,所以在这里可以用到匿名内部类:
直接实例化这个类,最后需要加分号,大括号之内写的内容就是这个类的类体
这样的写法就是一个匿名内部类,它的效果就相当于以下所示(注释掉的部分):
package inner_class;
public class Demo3 {
public OutInterface2 action() {
// return new innerClass2();
return new OutInterface2() { //匿名内部类
private int i = 0;
public int getValue() {
return i;
}
};
}
}
interface OutInterface2{
}
//class innerClass2 implements OutInterface2{
// private int i = 0;
// public int getValue() {
// return i;
// }
//}
为什么叫匿名内部类?
因为这个内部类在使用时才对它进行编写
静态内部类
我们发现x这个值 在静态内部类的方法里是不能用的(因为我这个类是静态类,静态的类只能调用静态的属性)
那会有这样一个疑问:它有这么多限制条件,我们为什么还要用它? 因为,它能做到其他类做不到的效果(我们可以在静态内部类中创建main方法)
之前我们讲过,主方法只能在主类中运行,而我们这个主方法竟然可以在 主类的静态内部类中运行
内部类有这样一个特点:将其中一个.java文件拷贝到C盘,然后打开控制台(一个java文件生成了两个class文件,因为我们这个代码中有两个类)
静态内部类最大的功能,就是给我们提供一个调试的功能。
将main方法写在静态内部类中,生成class文件之后,因为调试代码在静态内部类中,所以***将该class文件删掉,不会影响我外部类中的代码,仍然可以调用它,这就是静态内部类的特点***
package inner_class;
public class Demo4 {
int x = 100;
static class innerClass4{ //静态内部类
// x = 200;
public static void main(String[] args) {
System.out.println("我是静态内部类");
}
}
}
内部类的继承
在继承内部类的时候,必须要添加一个带参数的构造方法,参数则是我这个外部类的对象;在构造方法中,必须要***调用外部类的它的父类方法(d.super())***,只有这样写,才能为我继承的关系提供必要的对象引用,这种语法是强制的
package inner_class;
public class Demo {
class innerClass{ //成员内部类
}
public static void main(String[] args) {
}
}
class NewClass extends Demo.innerClass{ //内部类的继承
public NewClass(Demo d) {
d.super();
}
}