week03
day10
1.static关键字
static :共享,共用
静态static关键字的特点:
1).随着类的加载而加载;
2).优先于对象存在:不能与this共存 (this:代表当期类对象的地址值引用)
3).被静态修饰的,可以被多个对象共享.共享共用
4).被静态修饰的变量,方法(静态变量/静态方法)
成员变量、成员方法----->都指的是非静态
静态static的成员访问方式:类名.变量--->类变量
类名.方法名()-->类方法
静态static关键字的使用注意事项
1).非静态的方法:既可以访问静态变量,也可以访问非静态的变量
既可以调用静态方法,也可以调用非静态方法
2).静态的方法:只能访问静态变量
只能调用静态方法 (静态只能访问静态)
2.代码块
代码块:在java中,使用{}包裹起来的内容,称为代码块!
分类:
1).局部代码块:在方法定义中使用,作用:限定局部变量的生命周期
2).构造代码块:在类的成员位置(类中,方法外),使用{}包裹起来
作用:给类中的一些成员进行数据初始化
特点:每次在执行构造方法之前,如果存在构造代码块,先执行代码块中的内容!
3).静态代码块:在类的成员位置,直接使用static{},静态代码块就加载一次
特点:随着类的加载而加载,优先于对象存在!
作用:可以通过static{}代码块,对一些操作(IO流创建文件/JDBC(java链接数据库注册驱动))
优先级:静态代码块> 构造代码块>构造方法
3.继承(extends)
1).继承:将多个类的共性内容抽取到一个独立的类中,然后这多个类和独立的这个类产生一种关系:继承关系
格式:
class Fu{
}
class Zi extends Fu{
}
2).继承的好处:
1).提高代码的维护性!
2).提高代码的复用性!
3).让类与类之间产生的关系,是"多态的前提条件"
程序开发遵循一个原则:"低(松)耦合,高内聚"
实际开发中:耦合避免不了,但是可以降低(类与类之间的关系越少越好),
内聚:就是解决某件事件的能力(一个类能完成的事情,尽量一个类完成)
降低耦合性:可以通过反射(贯穿整个javaEE)来创建某个类的实例
3).继承的特点
类与类之间的关系:继承关系,只支持单继承
格式: class 子类名 extends 父类名{}
不支持多继承,但支持多层继承
class GrangFu{
}
class Fu extends GrandsFu{
}
class Zi extends Fu {
}
练习:
class GrandFather{
public void method(){
System.out.println("我是爷爷");
}
}
class Father extends GrandFather{
public void method() {
System.out.println("Father");
}
public void show(){
System.out.println("show Father..");
}
}
class Son extends Father{
public void Function(){
}
}
//测试类
public class ExtendsDemo {
public static void main(String[] args){
//创建类对象
Son.son = new Son();
son.function();
son.show();
son.method();
}
}
}
4)继承中使用的注意事项
1.子类继承父类:可以继承父类的非私有的成员,私有的成员外界不能访问,只能在本类中访问,可以通过公共方法间接访问.
2.构造方法是不能被继承的,但是子类可以间接通过super关键字访问父类的构造方法
如果一个A类是B类的一种,或者B类是A类的一种,这个时候就可以使用继承关系
继承关系:现实世界事物中本质体现的是一种"is a"的关系
4.继承(extends)成员访问
继承中:子类继承父类,如果子类的成员变量名称和父类的成员变量名称不一致,分别访问即可!
☆☆子类和父类的成员变量名称一致的情况,访问方法:(就近原则)
1).先在子类的局部位置中找,是否存在这个变量名称,如果存在,就使用;
2).如果不存在,那么就在子类的成员位置中找是否存在,如果存在,就使用
3).如果不存在,那么在父类的成员位置中找是否存在,如果存在,就使用
4).如果不存在,会报错,那说明没有这个变量.
继承中,子类访问父类的构造方法:
1).子类继承父类,子类的所有构造方法都会默认的访问父类的无参构造方法
子类的所有构造方法的第一句话:默认隐藏了super();因为子类可能会使用到父类的数据,所以在继承关系中得先让父类初始化--->构造方法:分层初始化(先让父类无参构造方法,在执行子类的构造方法)
super:代表的父类对象的空间标识(父类对象的地址值引用)
如果父类中的无参构造方法没有,子类的所有的构造都会报错(因为子类所有构造方法默认父类的无参构造方法)
解决父类没有无参构造的方法:
1).手动给出父类的无参构造方法
2).在子类的构造方法中的第一句话:通过super(xxx),间接的访问父类的有参构造方法
3).只要子类的所有构造方法中:this():--->访问本类的无参构造方法,然后在子类的无参构造方法中间接访问父类的有参构造方法:super(xxx);
开发中:子类的无参构造默认访问父类的无参构造方法,有参构造方法访问父类的有参构造方法
练习:
class Root{
static{
System.out.println("Root的静态初始化块"); //1)
}
{
System.out.println("Root的普通初始化块"); //4)
}
public Root(){
System.out.println("Root的无参数的构造器"); //5)
}
}
class Mid extends Root{
static{
System.out.println("Mid的静态初始化块");//2)
}
{
System.out.println("Mid的普通初始化块"); //6)
}
public Mid() {
System.out.println("Mid的无参数的构造器"); //7)
}
public Mid(String msg){
this();
System.out.println("Mid的带参数构造,其参数值:"+msg); //8)
}
}
class Leaf extends Mid{
static{
System.out.println("Leaf的静态初始化块"); //3)
}
{
System.out.println("Leaf的普通初始化块"); //9)
}
public Leaf(){
super("hello");
System.out.println("Leaf的构造器"); //10
}
}
public class LeafTest {
public static void main(String[] args) {
new Leaf();
}
}
---------------------------------------
Root的静态初始化块
Mid的静态初始化块
Leaf的静态初始化块
Root的普通初始化块
Root的无参数的构造器
Mid的普通初始化块
Mid的无参数的构造器
Mid的带参数构造,其参数值:hello
Leaf的普通初始化块
Leaf的构造器
day11
1.this和super的区别
this:代表的当前类对象的地址值引用
super:代表的父类对象的地址值引用(代表父类的空间标识)
访问成员变量:
this.变量名:访问的本类中的成员变量
super.变量名:访问的是父类的成员变量
访问构造方法:
this():访问本类的无参构造方法
super():访问的父类的无参构造方法
this(XXX):访问的本类的有参构造方法
super(XXX):访问的父类的有参构造方法
成员方法:
this.方法名():访问的是本类的成员方法
super.方法名():访问的是父类的成员方法
2.方法重写(override)
面试题:
方法重写和方法重载的区别:
方法重载:在一个类中,提供n多个功能,这些功能,方法名相同,参数列表不同,与返回值无关
参数列表:数据类型不同,参数个数不同,先后顺序
目的:提高某个功能的扩展性,同一个方法可以接收很多类型的参数
方法重写:如果子类出现了和父类一模一样的方法,这个子类将父类的功能覆盖(复写/重写),创建子类具体对象
直接方法该功能,使用的子类的功能
重写的目的:为了沿用父类的功能,并且还需要使用子类的功能
3.final关键字(状态修饰符)
子类如果出现和父类一模一样的方法声明,称为"方法重写";
在有的不想让子类重写父类的功能,父类的功能是独立的,java提供了关键字:final(最终的,无法更改的)
4.final关键字的特点
public static final 数据类型 变量名 = 初始化;
1).可以修饰类,该类不能被继承
2).可以修饰成员方法,成员方法不能重写!
3).可以修饰的变量,这个变量此时是一个常量(自定义常量)
☆☆☆面试题:
final,finally,finalize()的区别:
finally:处理异常用到
finalize():跟垃圾回收器有关系:回收内存中没有更多引用的对象
5.final修饰基本数据类型和引用数据类型的区别
final修饰基本数据类型:基本数据类型的对应的数据值不能在被赋值了,只能赋值一次!
final int a = xx
final修饰引用数据类型:引用数据类型对应的地址值不能被改变,修饰实例变量
day12
1.多态
一个事物在不同时刻不同形态
多态的前提条件:
1).必须存在继承关系(extends)
2).必须存在方法重写
子类需要覆盖父类的功能
3).必须有父类引用指向子类对象
class Fu{
XXX
}
class Zi extends Fu{
XXX
}
格式:Fu f = new Zi();
多态的成员访问特点:
Fu fu = new Zi();
1).针对成员变量的访问问题:
编译看左,(看父类是否存在变量,存在编译不会报错)
运行看左!(使用父类的东西)
2).针对多态中的成员方法的访问问题:(都是非静态的成员变量/成员方法)
编译看左,(看父类是否存在这个方法,存在编译不会报错)
运行看右(因为子类重写了父类的东西)
3).如果成员方法是静态方法:
编译看左,(看父类是否存在这个静态方法,存在,编译不会报错)
运行看左
4).构造方法:
存在继承关系,还需要让父类先初始化,然后再子类进行数据初始化!(分层初始化)
多态的好处
1).提高代码的复用性:由继承保证
2).提高了代码的扩展性:由多态保证
Fu fu = new Zi();父类引用可以指向子类对象 向上转型
多态的弊端
1).不能访问子类的特有功能
解决多态的弊端
方法1:具体的子类创建具体的子类对象
Zi z =new Zi(); 在堆内存中又开辟空间,比较消耗空间内存
z.成员方法名();
方法2:向下转型
多态的第三个前提条件:父类引用指向子类对象
向上转型: Fu f = new Zi();
将父类的引用转换成子类的引用,不需要在堆内存中开辟空间
向下转型: Zi z = (Zi) f; 还原成子类型
强转类型转换: 目标类型 变量名 = (目标类型)初始化值;
练习
南方人和北方人都有姓名,年龄以及性别,都有"吃饭"的功能,
但是南方人经常吃米饭,北方人经常吃面条,
南方人主要还去经商,北方人主要考学,
请使用面向对象编程并且使用多态形式进行测试南方人和北方人!
public class Person {
private String name;
private int age ;
private String gender;
public Person() {
}
public Person(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
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 getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
//都有"吃饭"的功能
public void eat(){
System.out.println("都需要吃饭");
}
}
public class SouthPerson extends Person{
public SouthPerson() {
}
public SouthPerson(String name, int age, String gender) {
super(name, age, gender);
}
@Override
public void eat() {
System.out.println("南方人喜欢吃大米");
}
//特有功能
public String business(){
return "喜欢经商";
}
}
public class NorthPerson extends Person {
public NorthPerson() {
}
public NorthPerson(String name, int age, String gender) {
super(name, age, gender);
}
@Override
public void eat() {
System.out.println("北方人喜欢吃面食");
}
public String study(){
return "喜欢考学";
}
}
public class PersonTest {
public static void main(String[] args) {
//多态测试
//测试南方人
Person p = new SouthPerson();
p.setName("张三");
p.setAge(20);
p.setGender("男");
System.out.println(p.getName()+"---"+p.getAge()+"----"+p.getGender());
p.eat();
//南方人的特有功能
//编译看左,运行看右
SouthPerson sp =(SouthPerson)p;
String spResult = sp.business();
System.out.println(spResult);
System.out.println("--------------------------");
//测试北方人
Person p2 = new NorthPerson("李四",44,"女");
System.out.println(p2.getName()+"---"+p2.getAge()+"----"+p2.getGender());
//向下转型,访问北方人的特有功能
NorthPerson np = (NorthPerson)p2;
String npResult = np.study();
System.out.println(npResult);
}
}
2.多态的向下转型使用不当
向下转型使用不当:就出现java.lang.ClassCastException:类转换异常:(属于运行时期异常),当前堆内存中的实例不是该类型时,就会出现问题
ArrayIndexOutOfBoundsException:数组角标越界异常---->extends
IndexOutOfBoundsException:角标越界异常:出现不存在的角标
StringIndexOutOfBoundsException:字符串角标越界异常--->extends
IndexOutOfBoundsException:角标越界异常
NullPointerException:空指针异常,是在描述当某一个对象通过一些功能被获取的时候可能为null,这个时候还使用当前对象调用方法,就会通过jvm抛出异常!
解决方案:针对某个对象进行非空判断
3.抽象类(abstract)
现实世界事物中,某个事物是比较概括性,描述为抽象事物
将某个事物中的一些功能仅仅给出声明即可,没有方法体--->抽象方法--->这个类必须为抽象类
abstract关键字
抽象方法的格式:
权限修饰符 abstract 返回值类型 方法名(形式参数列表);
抽象类的格式:
abstract class 类名{}
抽象类的特点:
1).有抽象方法的类一定是抽象类;
2).抽象类中不一定只有抽象方法,还可以有非抽象方法(有方法体)
3).抽象类不能实例化(不能创建对象),不能new
通过具体的子类进行实例化(进行对象的创建),抽象类多态 Fu fu = new Zi();Fu类型:抽象类型
核心宗旨:强制子类必须完成的事情(要将父类中所有的抽象方法必须重写,否则报错)
抽象类的成员特点:
成员变量:既可以定义变量,也可以是常量,被final修饰
成员方法:既可以定义为抽象方法,也可以定义为非抽象方法
如果定义为抽象方法,关键字abstract显示给出
构造方法:存在无参构造/有参构造方法---->目的:分层初始化
4.抽象类练习
/*雇员类(Employee-抽象类):包含抽象方法work() 和抽象方法 show()
work()方法表示 工作内容
show()方法表示 员工属性的介绍
程序员类和项目经理类都属于雇员
程序员类:属性(姓名、工号、工资、奖金),行为(工作:软件开发)
项目经理类:属性(姓名、工号、工资、奖金),行为(工作:控制进度)
要求:子类在实现时,用System.out.println()在控制台输出
例如: 程序员 work() 输出:"软件开发"
show() 输出:姓名为xxx 工号为xxx .....
*/
public abstract class Employee {
//将程序员与经理类的共性内容抽取到抽象类中
private String name; //姓名
private String ID; //工号
private int salary; //工资
private int bonus; //奖金
public Employee() {
}
public Employee(String name, String ID, int salary, int bonus) {
this.name = name;
this.ID = ID;
this.salary = salary;
this.bonus = bonus;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getID() {
return ID;
}
public void setID(String ID) {
this.ID = ID;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public int getBonus() {
return bonus;
}
public void setBonus(int bonus) {
this.bonus = bonus;
}
//包含抽象方法work(); 和抽象方法 show();
//work() 方法表示 工作内容
//show() 方法表示 员工属性的介绍
public abstract void work(); //显示工作内容
public abstract void show(); //显示员工信息介绍
}
//manager类
public class Manager extends Employee{
public Manager() {
}
public Manager(String name, String ID, int salary, int bonus) {
super(name, ID, salary, bonus);
}
@Override
public void work() {
System.out.println("主要工作是控制项目进度");
}
@Override
public void show() {
System.out.println("姓名为:"+super.getName()+",工号:"+super.getID()+",工资:"
+super.getSalary()+",奖金"+super.getBonus());
}
//特有功能
public void teach(){
System.out.println("教新来程序员写helloworld");
}
}
//programmer类
public class Programmer extends Employee{
//无参构造
public Programmer() {
}
//有参构造方法
public Programmer(String name, String ID, int salary, int bonus) {
super(name, ID, salary, bonus);
}
@Override
public void work() {
System.out.println("主要工作内容是软件开发");
}
@Override
public void show() {
System.out.println("姓名为:"+super.getName()+",工号:"+super.getID()+",工资:"
+super.getSalary()+",奖金"+super.getBonus());
}
//特有功能
public void coding(){
System.out.println("程序员配有鼓励师");
}
}
//测试类
public class EmployeeTest {
public static void main(String[] args) {
Employee emp = new Programmer("张三","1234",10000,3000);
emp.show();
emp.work();
//向下转型
Programmer pg = (Programmer) emp;
pg.coding();
Employee emp1 = new Manager("李四","1235",15000,1000);
emp1.show();
emp1.work();
//向下转型
Manager mg = (Manager) emp1;
mg.teach
}
}
day13
1.当子类继承父类的时候,如果存在方法重写,那么子类重写父类该方法访问权限不能更低!
2.类没有抽象方法_定义为抽象类的意义
☆☆☆面试题:
一个类中没有抽象方法,那么将这个类定义为抽象类的意义:为了不让它直接实例化
实例化的方法:它可能提供一些静态功能,静态功能的返回值类型是它本身
3.和abstract冲突的关键字
private冲突:私有的方法,只能在本类中访问,加入abstract目的需要被子类重写,需要调用子类的功能
static冲突:静态方法随着类的加载而加载,而静态方法的访问通过类名.方法名(),抽象方法没有方法体
final:被final修饰的成员方法是不能被重写的,加入abstract的方法需要被重写
4.abstract能够跟的关键字
public :默认修饰符
protected:受保护的(同一个包下的当前类或者子类中或者不同包下的子类)
5.接口(interface)
接口:比抽象类还抽象,它的本质就是体现一个现实世界事物所具有的的额外的扩展功能
定义格式:interface 接口名{} ----->接口名遵循"标识符规则"(大驼峰命名法)
接口中的方法:不能有方法体,隐藏public abstract关键字,只能抽象方法,不能有方法体
接口的特点:不能实例化,不能创建对象
实例化的方法:
接口实例化:通过接口的子实现类(具体类)进行实例化---接口多态
子实现类和接口的关系:implements 实现关系
接口的子实现类如果是抽象类,肯定存在抽象类的具体的子类,否则不能实例化
接口的子实现类的命名规则:
开发中,在接口名的后面+Impl:子实现类
接口的成员特点:
1).接口中的成员方法:只能是抽象方法,默认的修饰符:public abstract ...可以省略不写
2).接口中没有构造方法
3).接口的成员变量只能是常量:
存在默认修饰符:public static final(可以省略不写)
6.接口和抽象类的区别
1).成员的区别
抽象类:
成员变量:既可以存在变量,也可以是常量
成员方法:可以存在抽象方法(必须携带abstract关键字),也可以有非抽象方法
构造方法:存在无参构造/有参构造方法,需要给数据进行初始化,分层初始化
接口:
成员变量:只能是常量,存在默认的修饰符public static final修饰
成员方法:只能是抽象方法,存在默认的修饰符public abstract
构造方法:没有
2).关系的区别
类与类之间:继承关系(extends),只支持单继承,不支持多继承,但是可以多层继承
类与接口: 实现关系(implements),一个类继承另一个类的同时可以实现多个接口,中间逗号隔开
接口与接口:继承关系(extends),可以支持单继承,也可以支持多继承,多层继承
3).设计理念
抽象类:强制子类必须完成的事情,由于存在继承关系,体现的是一种"is a"的关系
接口:体现某个事物额外的功能,谁实现该接口就具备该功能,体现的是一种"like a"的关系
7.接口的练习
/*
* (1)定义一个接口CanCry,描述会吼叫的方法public void cry()
* (2)分别定义狗类(Dog)和猫类(Cat),实现CanCry接口。实现方法的功能分别为:
* 打印输出“我是狗,我的叫声是汪汪汪”、“我是猫,我的叫声是喵喵喵”
* (3)定义一个主类G,
* 定义一个void makeCry(CanCry c)方法,其中让会吼叫的事物吼叫。
* 在main方法中创建狗类对象(dog)、猫类对象(cat)、G类对象(g),用
* g调用makecry方法,让狗和猫吼叫。
*
* 考点:
* 1)接口定义
* 2)方法的形式参数传递的是一个接口类型
*
*/
//接口CanCry
public interface CanCry {
public void cry();
}
//定义猫类
public class Cat implements CanCry {
@Override
public void cry() {
System.out.println("我是猫,我的叫声是喵喵喵");
}
}
//定义狗类
public class Dog implements CanCry{
@Override
public void cry() {
System.out.println("我是狗,我的叫声是汪汪汪");
}
}
//定义G类
public class G {
public static void main(String[] args) {
Dog d = new Dog();
Cat c = new Cat();
G g = new G();
g.makeCary(d);
g.makeCary(c);
System.out.println("-----------------");
g.makeCary(new Dog());
g.makeCary(new Cat());
}
void makeCary(CanCry c) {//方法的形式参数是接口类型--->需要接口的子实现类对象
c.cry();
}
}
8.选择排序----思想以及核心代码
使用0角标对应的元素依次和后面角标对应的元素进行比较,小的往前放,第一次比较完毕,最小值出现在最小索引处,依次这样比较
比较的次数:数组长度-1次
//遍历
public static void printArray(int[] arr){
System.out.print("{");
for(int i = 0;i<arr.length;i++){
if(i==arr.length-1){
System.out.println(arr[i]+"}");
}else{
System.out.print(arr[i]+", ");
}
}
}
//选择排序
public static void selectSort(int[] arr){
for(int x =0;x<arr.length-1;x++){
for(int y=x+1;y<arr.length;y++){
if(arr[y] < arr[x]){
int temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
}
}
}
day14
1.形式参数问题(引用类型)
如果方法的形式参数是类,调用方法的时候,传递实际参数:
具体类:调用该方法,实际参数需要传递当前具体类的对象
抽象类:调用该方法实际参数需要传递的抽象类的子类对象(抽象类多态)
接口:调用该方式,实际参数需要传递的是当前接口的子实现类对象(接口多态)
2.返回值问题
如果一个方法的返回值是引用类型,最终方法结束
具体类:方法返回的就是当前具体的对象
抽象类:需要返回的是抽象类的子类对象
接口:需要返回的是该接口的子实现类对象
3.权限修饰符的权限范围
同一个包下的当前类中 同一个包下的子类中/无关类中 不同包下的子类 不同包下的无关类中
private √
默认修饰符 √ √
protected √ √ √
public √ √ √ √
修饰的权限从小到大依次:private 默认修饰符 protected public
4.内部类/外部类
1).内部类:在一个类中可以定义另一个
2).外部类:在类A中定义了类B,将类A就称为类B的外部类
3).成员内部类:在一个类的成员位置中定义了另一个类
4).内部类可以访问外部类的成员,包括私有!
5).外部类直接访问内部类的成员方法:
格式: 外部类名.内部类名 对象名 = 外部类对象.内部类对象
6).成员内部类的修饰符:
在成员内部类上面,加入private修饰,为了数据的安全性,它的访问,就要外部类的公共访问间接访问
7).如果当前成员内部类是静态的, 里面的方法无论是静态的还是非静态的,都只能访问外部类的静态成员,包括私有!
8)直接访问静态成员内部类的成员:
将静态的成员内部类看成是外部类的静态成员访问
直接访问方式:外部类名.内部类名 对象名 = new 外部类名.内部类名();