Day08课堂笔记
标签(空格分隔): java基础
代码块
- 概念:在java中,被{}括起来的代码,这个整体称为代码块
- 代码块分类:
- 局部代码块 :方法里面
举例:
- 局部代码块 :方法里面
public void test(){
{
//这是局部代码块,在方法里面
}
}
- 构造代码块 : 在类中,方法外,书写格式 : { }
作用:优先于构造方法执行,也就是说你创建对象的时候,优先执行,不管你是new空参还是有参都是优先执行
举例:
class Student {
{
//这就是构造代码块
System.out.println("构造代码块");
}
public Student(){
System.out.println("空参构造");
}
public void study(){
//方法
}
}
- 举例: Student s = new Student();
先输出 构造代码块 — 空参构造 - 静态代码块 格式: static { }
作用:随着类的加载而加载,并且只加载一次!
位置:类中方法外
举例:
class Student{
static{
//这个就是静态代码块
System.out.println("静态代码块");
}
}
举例:学习就业班的Mysql连接数据库的时候,加载数据库驱动,就是因为它只加载一次
同步代码块:学习多线程时候才学
注意: 这些代码块可以同样书写在一个类中,并不是说 一个类只能写一个,如果你写了多个,那就按照顺序执行!
举例:
class Student{
//类加载的时候 静态代码块跟着加载
static {
System.out.println("静态代码块1");
}
static {
System.out.println("静态代码块2");
}
// 创建对象的时候才调用
{
System.out.println("这是构造代码块1");
}
public void study {
//这个局部代码块 需要调用这个study方法才会调用
{
System.out.println("这是局部代码块");
}
}
}
关于在类中,能书写的成员有哪些?
错误案例举例:
class Student {
//书写错误,语法错
System.out.println("Hello World!");
}
书写 :成员变量 构造方法 普通成员方法 代码块 内部类
举例 :
class Student{
//静态代码块
static{
System.out.println("静态代码块");
}
//构造代码块
{
System.out.println("构造代码块");
}
//成员变量
private String name;
private int age;
//无参构造
public Student(){ }
//有参构造
public Student(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 study(){
System.out.println("普通成员方法");
}
//局部代码块
public void show(){
{
//这个是局部代码块
System.out.println(name +"----"+ age )
}
}
}
继承
为什么要用继承?
最重要: 其实就是为了提高代码的复用性!
不用继承行不行?
可以,大不了就多写重复的代码
什么关键字可以帮我们实现继承?
extends
举例
class BaseStudent{
String name;
int age;
public void study(){
System.out.println("学习");
}
}
class SuperStudent{
String name;
int age;
public void study(){
System.out.println("学习");
}
}
思考:如果两个类中间的代码都能够提出来,让我们共享那就好了
class Student {
String name;
int age;
public void study(){
System.out.println("学习");
}
}
这个时候我们只需要做一步,就可以把这些代码全部拿过来
改进后:
class BaseStudent extends Student{
}
class SuperStudent extends Student{
}
改进后的代码大大的明显减少了,只是增加了一个公共类
继承的好处和弊端(非常重要)
继承的好处和弊端分别是什么?
好处:提高代码复用性 ,维护性 ,让类和类之间产生关系,是多态的前提
弊端:耦合性增强
开发原则:高内聚 低耦合
内聚:自己能完成的事情就尽量自己完成
耦合:类和类之间关系密切
继承的特点
在java中,只支持单继承,不支持多继承,支持多层继承.
单继承举例:
class A{
public void show(){
System.out.println("A");
}
}
class B{
public void test(){
System.out.println("test");
}
}
//错误的书写 ,这个不支持,因为java只能支持单继承
class C extends A,B{
}
正确的书写
class C extends A{
}
或者
class C extends B{
}
多层继承
class A{
public void show(){
System.out.println("A");
}
}
class B extends A{
public void test(){
System.out.println("test");
}
}
class C extends B{
//相当简接继承了A
}
继承的使用注意点(记住)
- 什么时候使用继承?
符合一种” is a” .是什么的一种… - 使用继承的时候注意事项有哪些?
(1)子类只能继承父类里面非私有的成员
(2)子类不能继承父类的构造方法
set方法和get方法能否合并一起?
//反面案例 不正确
class Student {
private String name;
public Student(){
}
public Student(String name){
this.name = name;
}
public String setName(String name){
this.name = name;
return name;
}
}
//写功能模块的 ,一个功能点,写一个方法,不要什么都写,不要书写多余的功能
class MathDemo{
//求和
public int add(int a,int b){
int sum = a+b;
//这个输出代码是多余的,不要书写
System.out.println(sum);
return sum;
}
}
某物流公司 某X邦 一个功能不能超过100行代码,注释不能低于50%
继承中的成员关系
总结:使用变量遵循一个“就近原则”。局部位置有就使用,没有就去本类的成员位置找,有就使用;没有就去父类的成员位置找,有就使用,没有就报错。
举例:
class Fu{
int age = 10;
String name = "父";
}
class Zi{
String name = "子";
public void show(){
System.out.println(name); //就近原则
System.out.println(age); //子类没有就会用父亲的
}
}
this 和super关键字区别(理解)
this和super分别代表什么?this和super的使用区别有哪些?
区别 | this | super |
---|---|---|
是什么 | 指的是当前对象,谁调用我.我就代表谁 | 代表父类的引用 |
应用场景 | 本类 | 必须发生在子父类中,没有继承关系不能直接使用 |
成员变量 | 可以调用本类成员变量,也可以调用父类成员变量(前提是本类没有) | 只能用于调用父类的成员变量 |
构造方法 | 可以调用本类的构造方法 | 调用父类的构造方法 |
普通成员方法 | 可以调用本类的,也可以调用父类(前提:本类没有的情况下才可以调用) | 调用父类的成员方法 |
继承中构造方法中注意事项
为什么子类中的所有构造方法默认都会访问父类中的空参构造?
因为创建子类对象的时候,要先完成父类数据的初始化(成员变量)
举例
class Father{
int age;
String name;
Father(){
System.out.println("父类空参");
}
Father(String name ,int age){
System.out.println("父类有参");
this.name = name;
this.age = age;
}
}
class Son extends Father{
public Son(){
super();//调用的是无参!
}
}
继承中构造方法的注意事项
- 子父类中,构造方法的访问?
子类是否一定要访问父类中的构造方法,是否一定要访问无参构造?不一定,系统默认父类无参构造访问. - 如果父类中没有提供无参的构造方法,只有有参的,那么我们怎么解决?
如果不写任何会怎样? 报错! - 怎么解决?
解决方案一:要么你就手动书写调用父类里面的有参构造
解决方案二:要么你要用this关键字指向其他的构造方法,在其他的构造方法里面书写调用父类的有参构造
class Fu{
private String name;
private int age;
public Fu(String name,int age){
this.name = name;
this.age = age;
}
//---get set方法省略
}
//方案一
class Zi extends Fu{
public Zi(){
// super(); //这样写 编译会出错,因为父类里面没有无参构造,所以我们需要去解决这个问题
super("张三",18); //当你手动书写了super(参数)方法时候,系统就不再自动帮你书写super();
}
}
方案二
class Zi extends Fu{
public Zi(){
//super();
//这种方式实际上是间接的通过其他构造方法去访问父类的有参构造!
this("张三",18);
}
public Zi(String name,int age){
super(name,age); //调用父类的有参构造
}
}
面试题
class Test2_Extends {
public static void main(String[] args) {
Zi z = new Zi();
}
/*
1,jvm调用了main方法,main进栈
2,遇到Zi z = new Zi();会先将Fu.class和Zi.class分别加载进内存,再创建对象,当Fu.class加载进内存
父类的静态代码块会随着Fu.class一起加载,当Zi.class加载进内存,子类的静态代码块会随着Zi.class一起加载
第一个输出,静态代码块Fu,第二个输出静态代码块Zi
3,走Zi类的构造方法,因为java中是分层初始化的,先初始化父类,再初始化子类,所以先走的父类构造,但是在执行
父类构造时,发现父类有构造代码块,构造代码块是优先于构造方法执行的所以
第三个输出构造代码块Fu,第四个输出构造方法Fu
4,Fu类初始化结束,子类初始化,第五个输出的是构造代码块Zi,构造方法Zi
*/
}
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");
}
}
继承中的成员方法
在子父类中,出现不同名字的方法时候,调用时候是怎样?
假设先创建了子类对象,子类中继承了父类中方法,子类调用父类中的方法,直接调用就行.
出现同名字的时候?
如果是希望再次调用父类,要用super关键字去调用 ,如果只是为了调用子类的,直接调用
方法的重写(非常非常非常重要)
方法重写:
子父类中出现一模一样的方法,称为方法重写
方法重写的应用:
* 当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法。这样,即沿袭了父类的功能,又定义了子类特有的内容。
class Ios7 {
public void call() {
System.out.println("打电话");
}
public void siri() {
System.out.println("speak English");
}
}
class Ios8 extends Ios7 {
public void siri() {
super.siri();
System.out.println("说中文");
}
}
方法重写
- 方法重写的注意事项有哪些?
- 父类中私有的方法,子类不能重写
- 子类中要重写父类的方法时候,权限不能低于父类
- 父类中静态的成员方法,子类如果要重写,子类必须也是静态
思考题:方法重写和方法重载有什么区别?(1分钟)
方法重写和方法重载(非常重要)
区别 | Override方法重写 | Overload 方法重载 |
---|---|---|
位置 | 子父类中 | 本类 |
定义 | 子类出现和父类一模一样的方法 | 本类中,方法名相同,参数列表不同 |
返回值 | 最好一致(子父类) | 无关 |
案例(非常非常非常重)
学生和老师案例(没有使用继承)
学生和老师案例(使用继承)
//第十步:书写测试类
class Test4_Person {
//第十一步:书写测试类的主方法 因为虚拟机要从这里开始执行
public static void main(String[] args) {
//创建一个学生对象,这里使用的是无参构造方法
Student s1 = new Student();
//这里面用了set方法的赋值方式,最后调用成员方法
s1.setName("张三");
s1.setAge(23);
System.out.println(s1.getName() + "..." + s1.getAge());
s1.eat();
s1.study();
System.out.println("------------------");
//创建第二个学生对象,用的是有参构造,也可以赋值,就不需要调用set方法了.如果需要改名字呢,就要用set方法,因为构造函数只能赋值一次
Student s2 = new Student("李四",24);
//这下面调用的是成员方法
System.out.println(s2.getName() + "..." + s2.getAge());
s2.eat();
s2.study();
}
}
/*
* 使用继承后的学生和老师案例
*/
/*
因为之前我们写的时候很多代码重复,所以我们想到了 用继承的方式来简化代码,提高代码的复用性
思考:怎么做?
首先我们先观察学生和老师有没有哪些共性的成员(成员变量,成员方法),通过观察 我们发现name和age 还有eat方法都是共性的,所以我们想向上封装一个类来封装他们共同点
这个时候,怎么封装?学生和老师,都是属于人类,所以我们起个名字叫Person(人)
抽取出来后,开始书写共性.怎么书写
*/
//第一步: 写一个Person类
class Person {
//第二步:书写共同的成员变量
private String name; //姓名
private int age; //年龄
//第三步:书写父类无参构造
public Person() {} //空参构造
//第四步:书写父类有参构造
public Person(String name,int age) { //有参构造
this.name = name;
this.age = age;
}
//第五步:提供公共访问方式 get/set方法
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;
}
//第六步:抽取共同的成员方法
//思考?为什么不把study和teach都写在父类?
//因为study方法只是学生有,老师才有教学的方法,所以这里父类里面不书写这两个方法.留给子类去实现
public void eat() { //吃饭
System.out.println(name + "吃饭");
}
}
//第七步:开始书写子类 要使用extends关键字继承父类
class Student extends Person {
//第八步:要书写子类构造方法 无参和有参 为什么要书写?因为构造方法无法从父类里面继承过来的
public Student() {} //空参构造
public Student(String name,int age) {
super(name,age);
}
//第九步:书写子类的特有成员方法,这个方法是子类有的,父类没有,所以需要在子类里面去书写
public void study() {
System.out.println(this.getName() + "学习");
}
}
//同理,老师类也是这样书写
class Teacher extends Person {
public Teacher() {} //空参构造
public Teacher(String name,int age) {
super(name,age);
}
public void teach() {
System.out.println(this.getName() + "讲课");
}
}
猫狗案例
class Test5_Animal {
public static void main(String[] args) {
/*
Cat c1 = new Cat("花",4);
System.out.println(c1.getColor() + "..." + c1.getLeg());
c1.eat();
c1.catchMouse();
Dog d1 = new Dog("黑",2);
System.out.println(d1.getColor() + "..." + d1.getLeg());
d1.eat();
d1.lookHome();*/
MeiZi mm = new MeiZi("bo枝",15);
mm.dance();
}
}
class MeiZi
{
private int age;
private String name;
public MeiZi(){
}
public MeiZi(String name,int age){
this.name = name;
this.age = age;
}
public void dance(){
System.out.println(age + "岁的"+name +"妹子跳舞啦!");
}
}
/*
* A:猫狗案例分析
* B:案例演示
* 猫狗案例继承版
* 属性:毛的颜色,腿的个数
* 行为:吃饭
* 猫特有行为:抓老鼠catchMouse
* 狗特有行为:看家lookHome
*/
class Animal {
private String color; //毛的颜色
private int leg; //腿的个数
public Animal(){}
public Animal(String color,int leg) {
this.color = color;
this.leg = leg;
}
public void setColor(String color) { //设置颜色
this.color = color;
}
public String getColor() { //获取颜色
return color;
}
public void setLeg(int leg) { //设置腿的个数
this.leg = leg;
}
public int getLeg() { //获取腿的个数
return leg;
}
public void eat() { //吃饭
System.out.println("吃饭");
}
}
class Cat extends Animal {
public Cat() {} //空参构造
public Cat(String color,int leg) { //有参构造
super(color,leg);
}
public void eat() { //吃鱼
System.out.println("猫吃鱼");
}
public void catchMouse() { //抓老鼠
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public Dog() {} //空参构造
public Dog(String color,int leg) { //有参构造
super(color,leg);
}
public void eat() { //吃肉
System.out.println("狗吃肉");
}
public void lookHome() { //看家
System.out.println("看家");
}
}
final
- final关键字的特点有哪些?
修饰的类不能被继承
修饰方法 ,这个方法就不能被重写
修饰变量,这个变量就会变成常量,只能赋值一次
开发中常用的是修饰变量
举例public static final String USER_ITEM = "http://........";
//通常写在配置文件
final修饰局部变量的时候
修饰的是基本数据类型:其值不能被改变
修饰的是引用数据类型:地址值不能被改变,但是这个对象的(属性)成员变量可以被改变
final修饰变量的初始化时机
显式初始化
对象构造方法中初始化