构造方法是一个比较特殊的方法,通过构造方法可以完成对象的创建,以及实例变量的初始化(注意:实例变量没有赋值时系统会默认赋值,是在对象创建的时候赋值,在构造方法执行的过程中完成初始化的)
无参构造方法虽然里面什么都没写,但是这个方法体里面进行的实例变量默认值初始化。
只要没有给变量赋值,系统都会赋默认值
public class Student{
int no;
String name;
int age;
public Student(){
System.out.println("!!!");
}
public Student(int i){
no=i;
}
}
1.当一个类没有提供任何构造方法,系统会自动提供一个无参数的构造方法,该构造方法被称为:缺省构造器
2.当一个类中提供了构造方法,系统不会再提供无参构造方法
3.无参数构造方法,有参数构造方法都可以调用,支持方法重载,一个类中构造方法可以有多个。
方法重载特点:在同一个类中,方法名相同,参数列表不同。
构造方法通过new运算符调用
构造方法的语法结构:
[修饰符列表] 构造方法名(形式参数列表){
构造方法体
通常在构造方法体中给属性赋值,完成属性的初始化
}
注意:修饰符列表统一写public,不要写public static
构造方法名和类名必须一致
构造方法不需要指定返回值类型,也不能写void
普通方法的语法结构:
[修饰符列表] 返回值类型 方法名(形式参数列表){
方法体
}
public class Main{
public static void main(String[] args){
//调用普通方法 :类名.方法名
Main.doSome();
doSome();//在一个类里面可以省略类名
//调用构造方法
Student x=new Student();
}
public static void doSome(){
System.out.println("do some!!");
}
}
2.封装
作用:保证内部结构的安全性,屏蔽复杂、暴露安全
1.属性私有化
2.1个属性对外提供两个set和get方法,可以在set方法中设立关卡保证数据的安全性。
对外只提供接口
注意:java开发规范中有要求,set方法和get方法要满足以下格式。
public 返回值类型 get+属性名首字母大写(无参){
return xxx;
}
public void set+属性名首字母大写(有1个参数){
xxx = 参数;
}
public class Main{
public static void main(String[] args){
}
}
public class Person{
//通过private关键字
private int age;
//对外提供简单的调用入口,set,get方法,并且这两个方法都是实例方法
public int getAge(){
return age;
}
public void setAge(int nianling){
//在此位置上设置关卡
if(nianling<0||nianling>150){
System.out.println("对不起,年龄值不合法!");
return;
}
age=nianling;
}
}
3.static
对象被称为实例。
实例相关的有:实例变量、实例方法。
实例变量是对象变量,实例方法是对象方法。
实例相关的都需要先new对象,通过"引用."的方法去访问。
public class Main{
public static void main(String[] args){
//带有static的方法通过“类名.”的方式访问
Main.doSome();
//在同一个类中“类名"可以省略
doSome();
//需要先new出来,创建对象,然后访问
Main mt=new Main();//Main类有一个无参构造方法
mt.doOther();
}
public static void doSome(){
System.out.println("do Some");
}
//这个方法没有static,这样的方法被称为:实例方法(对象方法,对象级别的方法)
public void doOther(){
}
}
//空指针异常
//本质原因:空引用访问“实例相关的数据”
//实例变量,实例方法
public class NullPointer{
public static void main(String[] args){
User u=new User();
System.out.println(u.id);//0
u.doSome();
//引用变成null
u=null;
//id的访问需要对象的存在
//System.out.println(u.id);//空指针异常
//一个实例方法的调用也必须有对象的存在
//u.doSome();//空指针异常
}
}
class User{
int id;
//实例方法(对象相关的方法,对象级别的方法,对应对象级别的行为)
public void doSome(){
System.out.println("do Some");
}
}
static翻译为“静态的”,所有static修饰的都是类相关的,类级别的。
所有static修饰的都是采用"类名."的方式访问
static修饰的变量:静态变量
static修饰的方法:静态方法
变量的分类:
方法体中声明的变量:局部变量
方法体外声明的变量:成员变量
成员变量分为
实例变量
静态变量
只要是方法不管是静态方法、实例方法、构造方法,它们在运行的时候都是需要压栈
堆里存实例变量,栈里存局部变量
静态变量是在类加载时初始化,存储在方法区
如果这个类型的所有对象的某个属性值都是一样的,不建议定义为实例变量,浪费内存空间,建议定义为类级别特征,定义为静态变量,在方法区中只保留一份,节省内存开销。
实例变量一定使用""引用.",静态的也可以但是不建议
class VarTest{
//以下实例的都是对象相关的,访问时采用"引用.”的方式访问,需要先new对象
//成员变量中的实例变量
int i;
//实例方法
public void m1(){
}
//以下静态的,都是类相关的,访问时采用“类名.”的方式访问。不需要new对象
//成员变量中的静态变量
static int k;
//静态方法
public static void m2(){
}
}
类=属性+方法
属性描述状态,方法描述行为动作
public class StaticTest02{
public static void main(String[] args){
Chinese c1=new Chinese("111","张三");
Chinese c2=new Chinese();
System.out.println(Chinese.country);
System.out.println(c2.name);
System.out.println(c1.idCard);
//不会出现空指针异常
c1=null;
System.out.println(c1.country);
}
}
class Chinese{
String idCard;
String name;
static String country="中国";
public Chinese(){
//无参数
}
public Chinese(String num,String n){
idCard=num;
name=n;
}
}
静态方法不能访问实例变量
如果方法中直接访问了实例变量,该方法必须是实例方法
工具类方法一般都是静态的
静态代码块
静态代码块在类加载时执行且只执行一次
在main方法执行之前执行,按照自上而下顺序执行
作用:1.不常用
2.特殊的时刻,类加载,记录日志
public class StaticTest06{
static{
System.out.println("A");
}
static{
System.out.println("B");
}
//入口
public static void main(String[] args){
System.out.println("D");
}
static{
System.out.println("C");
}
}
实例代码块
实例语句块在类加载时不执行
只要是构造方法执行,在构造方法执行之前一定执行实例语句块
public class InstanceCode{
//入口
public static void main(String[] args){
System.out.println("Main begin");
new InstanceCode();
}
//实例语句块
{
System.out.println("实例语句块执行");
}
public InstanceCode(){
System.out.println("无参数构成方法");
}
public InstanceCode(String name){
System.out.println("有参数构成方法");
}
}
4.执行顺序
public class Main{
//静态变量在类加载时初始化,存在方法区
static int i=100;
//静态代码块在类加载时执行
//只要时代码都存在方法区
static{
//可以访问i
System.out.println("i="+i);
}
int k=111;//实例变量,在构造方法执行时内存空间才会开辟。
static{
//不能访问k
System.out.println("k="+k);
}
//入口(main方法执行之前实际上执行了很多代码)
public static void main(String[] args){
}
}
1.对于一个方法来说,方法体中的代码有顺序,自上而下
2.静态代码块1和静态代码块2
3.静态代码块和静态变量
一个类体中的方法没有顺序
5.this1.关键字
2.一个对象,一个this,this是一个变量一个引用,保存当前对象的内存地址,指向自身
-
this存储在堆内存中对象内部
-
this只能使用在实例方法中,谁调用这个实例方法,this就是谁。所以this代表的是:当前对象
-
this.大部分情况下是可以省略的
增强可读性且防止因为就近原则导致的误解
参数名和实例变量重名,实例变量在该方法中使用this.方式访问
-
不能使用在静态方法中
public class ThisTest02{
int i=100;
static int k=111;
public static void main(String[] args){
//错误,无法从静态上下文中引用非静态变量
//System.out.println(i);
System.out.println(ThisTest02.k);
System.out.println(k);
ThisTest02 tt=new ThisTest02();
System.out.println(tt.i);
}
}
public class Last{
public static void main(String[] args){
Husband h1=new Husband("111","张三","1999-10-11",null);
Wife w1=new Wife("222","李四","1989-11-10",h1);
h1.wife=w1;
}
}
class Husband{
String idCard;
String name;
String birth;
Wife wife;//引用类型
public Husband(){
}
public Husband(String s1,String s2,String s3,Wife w){
idCard=s1;
name=s2;
birth=s3;
wife=w;
}
}
class Wife{
String idCard;
String name;
String birth;
Husband husband;
public wife(){
}
public Wife(String s1,String s2,String s3,Husband h){
idCard=s1;
name=s2;
birth=s3;
Husband=h;
}
}
this除了可以使用在实例方法中,还可以使用在构造方法中
新语法:通过当前的构造方法去调用另一个本类的构造方法,可以使用以下语法格式.代码复用
需要注意的是:两个构造方法在同一个类中
且其只能出现在该构造方法中第一句,且只能出现一次
this(实际参数列表)
class Date{
private int year;
private int month;
private int day;
public Date(){
this(1970,1,1);
}
public Date(int year,int month,int day){
this.year=year;
this.month=month;
this.day=day;
}
public void setYear(int year){
this.year=year;
}
public int getYear(){
return year;
}
public void setMonth(int month){
this.month=month;
}
public int getMonth(){
return month;
}
public void setDay(int day){
this.day=day;
}
public int getDay(){
return day;
}
}
6.继承extends
作用:代码复用,有了继承关系才有了后期的方法覆盖和多态机制。
缺点:耦合度高,父类修改,子类受到牵连
特性:①java中只支持单继承,不支持多继承
class E extends A,B{
}
//错误
②子类继承父类,除构造方法不能继承之外,剩下的都 可以继承。但是私有的属性无法在子类中直接访问。
③java中的类没有显示的继承任何类,则默认继承Object类,即一个类与生俱来就有Object类中所有的特征
System.out.println()
System是一个类名,直接使用System.out,说明out是一个静态变量
System.out返回一个对象,然后采用“对象."的方式访问println()方法
当输出一个引用的时候,println方法会自动调用引用的toString()方法,因此重写其很有必要
7.方法的覆盖Override和多态方法覆盖
什么时候考虑方法覆盖Override:当子类继承父类之后,当继承过来的方法无法满足子类当前的业务需求时,子类有权对该方法重新编写,有必要进行”方法的覆盖"
什么时候考虑方法重载Overload:当一个类中如果功能相似,建议将名字定义一样
条件一:两个类必须要有继承关系
条件二:重写之后的方法和之前的方法具有:相同的返回值类型(对于返回值类型是基本数据类型时必须一样,引用数据类型变小可以,但意义不大,实际开发中没人这么写)、相同的方法名、相同的参数列表
条件三:访问权限(public>protected>private)不能更低,可以更高
条件四:重写之后的方法不能比之前的方法抛出更多的异常,可以更少
父类抛exception,子类可以抛也可也不抛也可以抛出范围更小的
注意事项:1.方法覆盖只是针对于方法与属性无关
2.私有方法无法覆盖
3.构造方法不能被继承,也不能被覆盖
4.方法覆盖只是针对于实例方法,静态方法覆盖没有意义
方法覆盖需要同多态机制联合起来才有意义
多态和对象有关系,而静态方法的执行不需要对象。
//静态方法不存在方法覆盖
public class OverrideTest05{
public static void main(String[] args){
Animal a=new Cat();
//静态方法和对象没有关系
a.doSome();//父类的方法,虽然使用"引用."来调,但是还是使用父类的方法
}
}
class Animal{
public static void doSome(){
System.out.println("An");
}
}
class Cat extends Animal{
public static void doSome(){
System.out.println("Ca");
}
}
私有方法无法覆盖
方法覆盖的返回值类型
public class OverrideTest07{
public static void main(String[] args){
}
}
class Animal{
}
class Cat extends Animals{
}
class MyClass1{
public Animal getAnimal(){
return null;
}
}
class MyClass2{
public Cat getAnimal(){
return null;
}
}
多态
1.多态的基础语法
java中允许向上转型(子-》父)与向下转型(父-》子),要求必须有继承关系
多态指的是:父类型引用指向子类型对象。包括编译阶段和运行阶段
编译阶段:绑定父类的方法
运行阶段:动态绑定子类型对象的方法
分析程序一定要分析编译阶段的静态绑定和运行阶段的动态绑定。
只有编译通过的代码才能运行,没有编译轮不到运行。
什么时候使用向下转型:访问的方法是子类中特有的方法,此时必须使用向下转型
ClassCastException类型转换异常
运算符:instanceof
①可以在运行阶段动态判断指向引用的对象的类型
②语法:(引用 instanceof 类型)
③运算结果只能是:true/false
④假设c是一个引用,c变量保存了内存地址指向了堆中的对象
(c instanceof Cat)为true表示:c引用指向的堆内存的java对象是一个Cat
(c instanceof Cat)为false表示:c引用指向的堆内存的java对象不是一个Cat
if(a6 instanceof Cat){
Cat y=(Cat)a6;
y.catchMouse();
}
2.多态在开发中的作用
软件开发原则:最基本原则:开闭原则(ocp):对扩展开放,对修改关闭
面向父类型编程
降低程序的耦合度,提高程序的扩展力
面向抽象编程
public class Homework{
public static void main(String[] args){
//创建各种乐器对象
Erhu erhu=new Erhu();
Piano piano=new Piano();
Violin violin=new Violin();
Musician m=new Musician();
m.play(erhu);
m.play(piano);
m.play(violin);
//还可以
m.play(new Erhu());
m.play(new Piano());
m.play(new Violin());
}
}
//乐器父类
class Instrument{
public void makeSound(){
}
}
//乐手
class Musician{
puclic void play(Instrument i){
//编译阶段makeSound方法是Instrument的,运行阶段不一定是谁的
i.makeSound();
}
}
//子类
class Erhu extends Instrument{
public void makeSound(){
System.out.println("二胡的声音");
}
}
//子类
class Piano extends Instrument{
public void makeSound(){
System.out.println("钢琴的声音");
}
}
//子类
class Violin extends Instrument{
public void makeSound(){
System.out.println("小提琴的声音");
}
}
super
1.this 能出现在实例方法中和构造方法中,不能使用在静态方法中
this.
this()只能出现在构造方法中,通过当前的构方法去调用“本类"中其他的构造方法,目的是:代码复用
2.super 能出现在实例方法中和构造方法中,不能使用在静态方法中
super.
super()只能出现在构造方法中,通过当前的构造方法去调用”父类“中的构造方法,目的时:创建子类对象的时候,先初始化父类特征。
当一个构造方法第一行,既没有this()又没有super()的话,默认会又一个super();表示通过当前子类的构造方法调用父类的无参数构造方法。所以必须保证父类的无参数构造方法是存在的。
注意:this(),super()不能共存
父类的构造方法一定会执行
在java语言中无论是构造什么方法,Object类的无参构造方法(处在栈顶)一定最先执行
class A{
public A{
}
public A(int i){
}
}
class B{
public B(){
//调用父类中有参数的构造方法
super(100);
}
}
在恰当的时间使用super(实际参数列表);
super代表“当前对象(this)”的父类型特征
注意:虽然在构造方法的执行过程中调用了父类的构造方法,父类的构造方法又向下继续调用其父类的构造方法,但是实际上对象只创建了一个
super用来创建当前父类型特征,super关键字代表的就是当前对象的那部分父类特征。
public class SuperTest04{
public static void main(String[] args){
Vip v=new Vip("张三");
v.shopping();
}
}
class Customer{
String name;
public Customer(){}
public Customer(String name){
super();
this.name=name;
}
}
class Vip extends Customer{
public Vip(){}
public Vip(String name){
super(name);
}
//super和this都不能出现在静态方法中。
public void shopping(){
//this表示当前对象
System.out.println(this.name+"正在购物!");
//super表示的是当前对象的父类型特征
System.out.println(super.name+"正在购物!");
//同一
System.out.println(name+"正在购物!");
}
}
当父类和子类中有同名属性,想访问父类中的属性需要加super.
super不是引用,也不保存内存地址,也不指向任何对象



