------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------
代码块:使用{}括起来的代码被称为代码块
局部代码块 :
在方法中出现;限定变量生命周期,及早释放,提高内存利用率
构造代码块:
多个构造方法方法中相同的代码存放到构造代码块中
每次调用构造方法,构造代码块都会执行,并且在构造方法前执行
静态代码块:
并加上static修饰;用于给类进行初始化,
在加载的时候就执行,并且值执行一次
代码块的面试题:
class Demo {
//静态代码块
static {
System.out.println("aaa");
}
//构造代码块
{
System.out.println("bbb");
}
//构造方法
public Demo(){
System.out.println("ccc");
}
//构造代码块
{
System.out.println("ddd");
}
//静态代码块
static {
System.out.println("eee");
}
}
class CodeBlockTest {
//静态代码块
static {
System.out.println("000");
}
public static void main(String[] args) {
new Demo();
System.out.println("---------");
new Demo();
System.out.println("---------");
new Demo();
System.out.println("---------");
}
}
结果为:
000
aaa
eee
bbb
ddd
ccc
-------
bbb
ddd
ccc
--------
bbb
ddd
ccc
继承:
概念:继承是从已有的类中派生出新的类,
新的类能吸收已有类的数据属性和行为,并能扩展新的能力。
继承的好处和弊端
提高了代码的复用性
多个类相同的成员可以放到同一个类中
提高了代码的维护性
如果功能的代码需要修改,修改一处即可
让类与类之间产生了关系,是多态的前提
其实这也是继承的一个弊端:类的耦合性很强
继承案例:
//父类
class Person {
private String name;
private int age;
//构造方法
public Person(){}
public Person(String name, int age){
this.name = name;
this.age = age;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
}
//子类
//class 子类 extends 父类 {...}
class Student extends Person { }
class Teacher extends Person { }
class ExtendsDemo2 {
public static void main(String[] args) {
//创建学生对象
Student s = new Student();
//赋值
s.setName("王二麻子");
s.setAge(28);
//获取值
System.out.println( s.getName() +"---" + s.getAge() );
System.out.println("-------------------------");
//创建老师对象
Teacher t = new Teacher();
//赋值
t.setName("王麻子老师");
t.setAge(38);
//获取值
System.out.println( t.getName() +"---" + t.getAge() );
}
}
继承特点
Java只支持单继承,不支持多继承
Java支持多层继承(继承体系)
例如:class GrandFather {
}
class Father extends GrandFather {
}
class Son extends Father{
}
class Mother {
}
//class Son extends Father,Mother {}//错误
//class Son extends Father {}//Java只支持单继承,不支持多继承
继承的注意事项:
子类只能继承父类所有非私有的成员(成员方法和成员变量)
其实这也体现了继承的另一个弊端:打破了封装性
子类不能继承父类的构造方法,
但是可以通过super(后面讲)关键字去访问父类构造方法
不要为了部分功能而去继承
class Father {
private int num = 10;
int num2 = 20;
//构造方法
public Father(){}
public Father(int num, int num2){
this.num = num;
this.num2 = num2;
}
//方法
private void method1(){
System.out.println(num);
System.out.println(num2);
}
public void method2(){
System.out.println(num);
System.out.println(num2);
}
}
class Son extends Father {
}
class ExtendsDemo4 {
public static void main(String[] args) {
//创建Son对象
Son s = new Son();
//变量
//System.out.println( s.num );//错误: num可以在Father中访问private
//System.out.println(s.num2);
//方法
//s.method1();//错误,method1()可以在Father中访问private
s.method2();
//----------------------
//子类不能继承父类的构造方法
//Son s2 = new Son(10,20);
}
}
我们到底在什么时候使用继承呢?
继承中类之间体现的是:”is a”的关系。
例如: Person
Student 学生是一个人
Teacher 老师是一个人
水果
菠萝 菠萝是一个水果
草莓 草莓是一个水果
白菜 它不能继承
继承中成员变量的关系
在子类方法中访问一个变量
首先在子类局部范围找
然后在子类成员范围找
最后在父类成员范围找(肯定不能访问到父类局部范围)
如果还是没有就报错。(不考虑父亲的父亲…)
(面试题)this和super的区别
this 代表本类对应的引用
super代表父类存储空间的标识(可以理解为父类引用)
用法(this和super均可如下使用)
访问成员变量
this.成员变量 super.成员变量
访问构造方法(子父类的构造方法问题讲)
this(…) super(…)
访问成员方法(子父类的成员方法问题讲)
this.成员方法() super.成员方法()
(面试题)
class Father {
int num = 10;
}
class Son extends Father {
int num = 20;
public void show () {
int num = 30;
System.out.println(num);//打印出30
System.out.println(this.num);//打印出20
System.out.println(super.num);//打印出10
}
}
class ExtendsDemo6 {
public static void main(String[] args) {
new Son().show();
}
}
继承中构造方法的关系
子类中所有的构造方法默认都会访问父类中空参数的构造方法
因为子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化。
每一个构造方法的第一条语句默认都是:super()
继承中构造方法的注意事项:
子类通过super去显示调用父类其他的带参的构造方法
super(参数列表)
子类通过this去调用本类的其他构造方法
this(参数列表)
一定要注意
super(…)或者this(….)必须出现在第一条语句上
否则,就会有父类数据的多次初始化
(面试题)
class Fu {
static {
System.out.println("静态代码块Fu");
}
{
System.out.println("构造代码块Fu");
}
public Fu() {
System.out.println("构造方法Fu");
}
}
class Zi extends Fu {
static {
System.out.println("静态代码块Zi");
}
{
System.out.println("构造代码块Zi");
}
public Zi() {
System.out.println("构造方法Zi");
}
}
Zi z = new Zi(); 请执行结果。
A:静态随着类的加载而加载。
B:静态代码块 -- 构造代码块 -- 构造方法的执行流程
静态代码块 -- 构造代码块 -- 构造方法
C:只要有子父关系,肯定先初始化父亲的数据,然后初始化子类的数据。
结果:
静态代码块Fu
静态代码块Zi
构造代码块Fu
构造方法Fu
构造代码块Zi
构造方法Zi
方法重写
子类中出现了和父类中一模一样的方法声明,也被称为方法覆盖,方法复写。
方法的重写与重载的区别?
方法的重写
子类中出现了和父类中一模一样的方法声明,也被称为方法覆盖,方法复写。
方法的重载
在同一个类中,多个方法的名称相同,参数列表不同(个数不同,数据类型方法)
使用特点
如果方法名不同,就调用对应的方法
如果方法名相同,最终使用的是子类自己的
方法重写的应用:
当子类需要父类的功能,而功能主体子类有自己特有内容时,
可以重写父类中的方法,
这样,即沿袭了父类的功能,又定义了子类特有的内容
方法重写的注意事项:
1:父类中私有方法不能被重写
2:子类重写父类方法时,访问权限不能更低
3:父类静态方法,子类也必须通过静态方法进行重写。
其实这个算不上方法重写,但是现象确实如此,
至于为什么算不上方法重写,多态中我会讲解
关于继承的标准代码:
//人类
class Person {
//成员变量
private String name;
private int age;
//构造方法
public Person(){}
public Person(String name, int age){
this.name = name;
this.age = age;
}
//对外提供公共访问方法,用来访问私有的成员变量的
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge(){
return age;
}
//睡觉方法
public void sleep(){
System.out.println("睡觉");
}
}
//学生类
class Student extends Person {
//注意了,构造方法不继承
public Student(){
super();
}
public Student(String name, int age){
super(name, age);
//this.name = name;//错误: name可以在Person中访问private
//this.age = age;//错误: age可以在Person中访问private
}
//重写父类方法
public void sleep(){
System.out.println("在教室睡觉");
}
//特有方法-->学习方法
public void study(){
System.out.println("学习");
}
}
//老师类
class Teacher extends Person {
public Teacher(){
super();
}
public Teacher(String name, int age){
super(name, age);
}
//重写父类方法
public void sleep(){
System.out.println("每天回家睡觉");
}
//特有方法 --> 工作方法
public void work() {
System.out.println("工作");
}
}
class ExtendsDemo13 {
public static void main(String[] args) {
//创建学生对象
Student s1 = new Student();
s1.setName("天下至尊");
s1.setAge(400);
System.out.println(s1.getName()+"---"+s1.getAge());
s1.sleep();
s1.study();
System.out.println("---------------");
//构造方法的方式赋值
Teacher t2 = new Teacher("天下", 500);
System.out.println(t2.getName()+"---"+t2.getAge());//结果:报错?
t2.sleep();
t2.work();
}
}
final关键字
final关键字是最终的意思
修饰类,类不能被继承
修饰变量,变量就变成了常量,只能被赋值一次
修饰方法,方法不能被重写
多态:
概念: 一个事物的多种形态
多态前提和体现
有继承关系或者实现关系
有方法重写
有父类引用指向子类对象
成员访问特点
方法的运行看右边,其他都看左边
多态的好处
提高了程序的维护性(由继承保证)
提高了程序的扩展性(由多态保证)
多态的弊端:
父类不能访问子类的特有方法
如果非要访问,向下转型(强转)
向上转型
从子到父
父类引用指向子类对象
向下转型
从父到子
父类引用转为子类对象
多态完整版案例:
//动物类
class Animal {
public void eat(){
System.out.println("吃饭");
}
}
class Cat extends Animal {
//重写父类方法
public void eat(){
System.out.println("猫吃鱼");
}
//特有方法
public void playGame(){
System.out.println("猫钓鱼");
}
}
class Dog extends Animal {
//重写父类方法
public void eat(){
System.out.println("狗吃肉");
}
//特有方法
public void lookHome(){
System.out.println("狗看家");
}
}
class Test {
public static void main(String[] args) {
//多态的方式
Animal an = new Dog();
an.eat();
//an.lookHome(); Dog类特有方法
System.out.println("-------------");
Dog dog1 = (Dog)an;// an 是狗
dog1.eat();
dog1.lookHome();
System.out.println("-------------");
an = new Cat(); // an 是猫
an.eat();
//an.playGame();// Cat类特有方法
System.out.println("-------------");
Cat cat1 = (Cat)an;
cat1.eat();
cat1.playGame();
System.out.println("-------------");
Dog dog2 = (Dog)an; //狗 d = (狗)猫;// 猫不能转换为狗
//ClassCastException 类型转换异常
}
}
抽象类:
抽象类:包含抽象方法的类,就是抽象类。 需要使用关键字 abstract修饰
抽象方法:只有方法声明,没有方法体, 需要使用关键字 abstract修饰
抽象类特点
1:抽象类和抽象方法必须用abstract关键字修饰
格式
abstract class 类名 {}
public abstract void eat();
2:抽象类不一定有抽象方法,有抽象方法的类一定是抽象类
3:抽象类不能实例化
那么,抽象类如何实例化呢?
按照多态的方式,由具体的子类实例化。
其实这也是多态的一种,抽象类多态。
4:抽象类的子类
要么是抽象类
要么重写抽象类中的所有抽象方法
注意:想创建对象,必须要将所有的抽象方法实现,才能创建对象
抽象类的成员特点:
成员变量
可以是变量
也可以是常量(final修饰的变量)
构造方法
有构造方法,但是不能实例化
那么,构造方法的作用是什么呢?
用于子类访问父类数据的初始化
成员方法
可以有抽象方法 限定子类必须完成某些动作
也可以有非抽象方法 提高代码服用性
abstract不能和哪些关键字共存
private 冲突
final 冲突
static 无意义
抽象类标准案例代码:
//员工类
abstract class Employee {
private String name;
private String id;
private double salary;
//构造方法
public Employee (){}
public Employee(String name, String id, double salary){
this.name = name;
this.id = id;
this.salary = salary;
}
//setXxx() getXxx()
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setId(String id){
this.id = id;
}
public String getId(){
return id;
}
public void setSalary(double salary){
this.salary = salary;
}
public double getSalary(){
return salary;
}
//抽象方法
public abstract void work();
}
//经理
class Manager extends Employee {
//成员变量 奖金
private double bonus;
//构造方法
public Manager(){}
public Manager(String name, String id, double salary, double bonus){
super(name, id ,salary);
this.bonus = bonus;
}
//setXxx getXxx
public void setBonus(double bonus){
this.bonus = bonus;
}
public double getBonus(){
return bonus;
}
//重写抽象方法
public void work(){
System.out.println("了解客户的需要,进行需求分析,带领团队走上巅峰");
}
}
//程序员:Programmer
class Programmer extends Employee {
//构造方法
public Programmer(){}
public Programmer(String name, String id, double salary){
super(name, id ,salary);
}
//重写抽象方法
public void work(){
System.out.println("不断的敲代码,不断的产生新的Bug");
}
}
class AbstractTest3 {
public static void main(String[] args) {
//创建对象
Manager m = new Manager("李总监", "itcast110", 80, 25.5);
System.out.println(m.getName() +"---"+ m.getId() +"---"+ m.getSalary() +"---"+ m.getBonus() );
m.work();
System.out.println("=============================");
Programmer p = new Programmer("张三", "itcast251", 8.8);
System.out.println(p.getName() +"---"+ p.getId() +"---"+ p.getSalary());
p.work();
}
}
接口:
接口特点
接口用关键字interface表示
格式:interface 接口名 {}
类实现接口用implements表示
格式:class 类名 implements 接口名 {}
接口不能实例化
那么,接口如何实例化呢?
按照多态的方式,由具体的子类实例化。
其实这也是多态的一种,接口多态。
接口的子类
要么是抽象类
要么重写接口中的所有抽象方法
接口成员特点
成员变量
只能是常量
默认修饰符 public static final
构造方法
没有,因为接口主要是扩展功能的,而没有具体存在
成员方法
只能是抽象方法
默认修饰符 public abstract
类与类关系:
继承关系,只能单继承,但是可以多层继承
类与接口关系:
实现关系,可以单实现,也可以多实现
还可以在继承一个类的同时实现多个接口
接口与接口关系:
继承关系,可以单继承,也可以多继承
(面试题)抽象类和接口的区别?
A)成员区别
抽象类
变量,常量、抽象方法、非抽象方法
接口
常量、抽象方法
B)关系区别
类与类
继承,单继承
类与接口
实现,单实现,多实现
接口与接口
继承,单继承,多继承
C)设计理念区别
抽象类 被继承体现的是:”is a”的关系。共性功能
接口 被实现体现的是:”like a”的关系。扩展功能
关于接口的标准代码案例:
//跳高接口
interface Jumpping {
public abstract void jump();
}
//动物类
abstract class Animal {
//成员变量
private String name;
//构造方法
public Animal(){}
public Animal(String name){
this.name = name;
}
//setXxx getXxx
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
//eat(抽象方法)
public abstract void eat();
}
//猫 extends 动物 implements 跳高接口
class Cat extends Animal implements Jumpping {
//构造方法
public Cat(){}
public Cat(String name){
super(name);
}
//实现所有的抽象方法
public void eat(){
System.out.println("猫吃鱼");
}
public void jump(){
System.out.println("跳高");
}
}
//狗 extends 动物
class Dog extends Animal {
//构造方法
public Dog(){}
public Dog(String name){
super(name);
}
//实现所有的抽象方法
public void eat(){
System.out.println("狗吃肉");
}
}
class InterfaceTest1 {
public static void main(String[] args) {
//猫
Cat c = new Cat("小花");
System.out.println( c.getName() );
c.eat();
c.jump();
System.out.println("------------");
//多态方式
Animal an = c;
System.out.println(an.getName());
an.eat();
//an.jump();
System.out.println("------------------");
//狗
Dog d = new Dog("小白");
System.out.println( c.getName() );
d.eat();
System.out.println("------------");
//多态方式
Animal an2 = d;
System.out.println(an.getName());
an2.eat();
//an.jump();
}
}
形式参数和返回值问题
形式参数:
基本类型:
引用类型:
具体类 : 参数列表中要接收的是,具体类的实例对象
抽象类 : 参数列表中要接收的是,子类的实例对象
接口 : 参数列表中要接收的是,实现接口的类的实例对象
返回值:
基本类型:
引用类型:
具体类 : 返回结果是,具体类的实例对象
抽象类 :返回结果是,子类的实例对象
接口 :返回结果是,实现接口的类的实例对象
链式编程
new Outer().method().show();
每一次方法调用完毕后,都会返回一个对象,
用返回的对象继续调用方法,再返回对象,再调用方法....
包(package):
包 可以理解为 就是文件夹
包 是用来存储多个.class类的
包 对类进行分类管理
包的格式:
package 包名;
多级包之间,使用.分隔
包的划分:
举例:
学生的增加,删除,修改,查询
老师的增加,删除,修改,查询
以及以后可能出现的其他的类的增加,删除,修改,查询
基本的划分:按照模块和功能分。
按照模块:
cn.itcast.teacher
AddTeacher、DeleteTeacher、UpdateTeacher、 FindTeacher
cn.itcast.student
AddStudent、DeletetStudent、UpdateStudent、FindStudent
按照功能:
cn.itcast.add
AddTeache、rAddStudent
cn.itcast.delete
DeleteTeacher 、DeletetStudent
cn.itcast.update
UpdateTeacher、UpdateStudent
cn.itcast.find
FindTeacher、FindStudent
-----------------------------------
注意事项:
package语句必须是程序的第一条可执行的代码
package语句在一个java文件中只能有一个
如果没有package,默认表示无包名
带有包的Java程序如何编译运行:
1:手动
a: 编译java文件,产生class文件
b: 创建包所对应的多层文件夹,把class文件放到最低层文件夹中
c: 运行 java 包名.类名方式访问
2: 自动创建包
a: 编译java文件,产生对应的包,把class文件放入包的最底层
javac -d . 文件名.java
b: 运行 java 包名.类名方式访问
同包下类之间的访问:
导包格式
import 包名.类名;
import 包名.*;//不建议
注意:
这种方式导入是到类的名称。
package,import,class有没有顺序关系(面试题)
package --> import --> class
在一个java文件中,只能有一个package
可以有多个import
可以有多个class,通常一个java文件中对应一个类
四种权限修饰符:
当前类中 同一个包下(子类和其他类) 不同包下的子类 在不同包下的其他类
private Y
默认 Y Y
protected Y Y Y
public Y Y Y Y
类及其组成可以用的修饰符:
权限修饰符: private 默认 protected public
状态修饰符: static final
抽象抽象符: abstract
类:
权限修饰符: 默认 public
状态修饰符: final
抽象抽象符: abstract
最常用的就是 public
成员变量:
权限修饰符: private 默认 protected public
状态修饰符: static final
最常用的就是 private
构造方法:
权限修饰符: private 默认 protected public
最常用的就是 public
成员方法:
权限修饰符: private 默认 protected public
状态修饰符: static final
抽象抽象符: abstract
最常用的就是 public
内部类:
把类定义在其他类的内部,这个类就被称为内部类。
class Outer{
class Inner{}//内部类
}
(面试题)内部类的访问特点:
内部类可以直接访问外部类的成员,包括私有。
外部类要访问内部类的成员,必须创建对象。
内部类的分类:
成员内部类: 类中方法外
局部内部类: 方法内
成员内部类的使用
格式:
外部类名.内部类名 对象名 = new 外部类名().new 内部类名();
成员内部类的修饰符:
private: 提高安全性
static : 方便内部类的访问
内部类面试题:
class Outer {
//this 对象
public int num = 10;
class Inner {
//this 对象
public int num = 20;
public void show() {
int num = 30;
System.out.println(num);//30
System.out.println(this.num);//20
//System.out.println(new Outer().num );
System.out.println( Outer.this.num );//10
}
}
}
class InnerClassDemo5 {
public static void main(String[] args) {
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
(面试题)局部内部类访问局部变量
必须被final修饰?
为什么呢?
因为局部变量会随着方法的调用完毕而消失,
这个时候,局部对象并没有立马从堆内存中消失,还要使用那个变量。
为了让数据还能继续被使用,就用fianl修饰,
这样,在堆内存里面存储的其实是一个常量值。
例题:
//外部类
class Outer {
//成员变量
private int num = 10;
public void method(){
//局部变量
//int num2 = 20;
final int num2 = 20;
//局部内部类
class Inner {
//成员变量
private int num3 = 30;
public void show(){
System.out.println(num);//10
//错误: 从内部类中访问本地变量num2; 需要被声明为最终类型 final
System.out.println(num2);//20
System.out.println(num3);//30
}
}
//创建一个内部类对象,调用show()方法
new Inner().show();
}
}
class InnerClassDemo6 {
public static void main(String[] args) {
//创建外部类对象,调用method()方法
Outer ou = new Outer();
ou.method();
}
}
匿名内部类,就是没有名字的内部类,它是内部类的简化写法。
前提:存在一个类或者接口
这里的类可以是具体类也可以是抽象类。
格式:
new 类名或者接口名() {
重写方法;
};
本质:
是一个继承了类或者实现了接口的子类匿名对象
匿名内部类:
理解为继承了一个类或者是实现了一个接口的子类,
并且完成了子类对象的创建,
同时子类对象没有名字