所谓的类就是指共性的概念,就是一类事物的总称,类似于一个模板;对象是事物存在的实体,通常又会将对象划分为两个部分,对象的属性和对象的行为⽽对象指的是⼀个具体的、可以使⽤的事物。
类是封装对象的属性和行为的载体,对象则是类的实例。
定义与使⽤
Person类的定义
class Person{
public String name;
public int age;
public Person(String name,int age){
this.name = name ;
this.age = age ;
}
public String getPersonInfo(){
return "姓名:"+this.name+",年龄:"+this.age;
}
}
**⽣产对象的语法**
类名称 对象名称 = new 类名称();
Person p1 = new Person();
Person p2 = new Person("Steven",25);
通过对象调⽤实例变量与实例⽅法
Person p = new Person("Steven",25);
System.out.println(p.name);
System.out.println(p.getPersonInfo());
只要出现了关键字new,就开辟了内存
对象内存分析
我们可以简单的将Java中的内存区域分为栈内存和堆内存两块区域:栈内存(虚拟机局部变量表):存放的是局部变量(包含编译期可知的各种基本数据类型、对象引⽤-即堆内存的地址,可以简单的理解为对象的名称),Java栈是与线程对应起来的,每当创建⼀个线程,JVM就会为这个线程创建⼀个对应的Java栈。
堆内存:保存的是真正的数据,即对象的属性信息。
class Person{
String name;
int age;
}
public class Test{
public static void main(String[] args) {
Person per = new Person();
per.name = "张三" ;
per.age = 18 ;
}
对象(引⽤数据类型)必须在实例化后调⽤,否则会产⽣ NullPointerException (运⾏时错误),
编译时不会出错。
NullPointerException 在各位今后的开发⽣涯中会⼀直存在,只有引⽤类型(数组、类、接⼝)才
会产⽣此类异常。以后出现此类异常,就根据出错位置查看引⽤类型变量是否初始化。
引⽤传递分析:⼀块堆内存可以被多个栈内存所指向
Person per1 = new Person();
Person per2 = new Person();
per2 = per1 ;
封装和构造⽅法
private实现封装
使⽤private封装属性
class Person{
private String name;
private int age;
public void setName(String n){
name = n ;
}
public String getName(){
return name;
}
public void setAge(int i){
if (i>0&&i<=200) {
age = i ;
}else {
age = 0 ;
}
} public int getAge(){
return age;
}
public void getPersonInfo(){
System.out.println("姓名:"+name+",年龄:"+age);
}
}public class Test{
public static void main(String[] args) {
Person person = new Person();
person.setName("张三");
person.setAge(-200);
person.getPersonInfo();
}
}
private实现封装的最⼤特征:只允许本类访问,⽽不允许外部类访问
类的设计原则
编写类时,类中的所有属性必须使⽤private封装。
属性若要被外部访问,必须定义setter、getter⽅法。
1.任何对象都应该有其对应的类,类是对象的蓝图
2.是⼀个唯⼀的标记,引⽤⼀块堆内存
3.表示开辟新的堆内存空间
4.构造⽅法
通过以上分析可以得知,所谓的构造⽅法就是使⽤关键字new实例化新对象时来进⾏调⽤的操作⽅法。
对于构造⽅法的定义,也需要遵循以下原则:
1.⽅法名称必须与类名称相同
2.构造⽅法没有返回值类型声明
3.每⼀个类中⼀定⾄少存在⼀个构造⽅法(没有明确定义,则系统⾃动⽣成⼀个⽆参构造)
问题:构造⽅法⽆返回值,为什么没有void声明?
回答该问题前我们看看现在类中的组成:属性、构造⽅法、普通⽅法。
1.属性是在对象开辟堆内存时开辟的空间
2.构造⽅法是在使⽤new后调⽤的
3.普通⽅法是在空间开辟了、构造⽅法执⾏之后可以多次调⽤的
public void Person(){} //命名不标准的普通⽅法
public Person(){} //⽆参构造⽅法
构造⽅法重载
public Person(){
System.out.println("===⽆参构造===");
}
public Person(String n){
name = n ;
System.out.println("===有参构造===");
}
this关键字
- this调⽤本类属性
- this调⽤本类⽅法
- this表示当前对象
static关键字
static修饰的属性被多个实例所共享,它不依赖实例。而且static修饰的属性被称为“类的成员”,”静态成员”。反之,没有被static修饰的属性,它依赖实例。而且没有被static修饰的属性被称为“实例成员”、“对象成员”。
访问static属性(类属性)应使⽤类名称.属性名
所有的⾮static属性(实例变量)必须在对象实例化后使⽤,⽽static属性(类属性)不受对象实例化控制
内部类的基本概念
内部类:所谓内部类就是在⼀个类的内部进⾏其他类结构的嵌套的操作
实例内部类(成员)
静态内部类
本地内部类(了解)
匿名内部类 (回调函数)
1.如何解决内部类问题 通过外部类访问内部类
2.实力内部类 能否定义static的数据成员? 能 static 后加final(常量)
3.实例内部类对象是否有额外的内存消耗? 有 实力内部类拥有外层内部类的this引用
4.静态内部类能否访问外部类的实例数据成员? 确实可以
在使⽤内部类的时候创建内部类对象 外部类.内部类 内部类对象 = new 外部类().new 内部类();
Outter.Inner in = new Outter().new Inner();
在外部类内部创建内部类对象 Inner in = new Inner();
成员内部类
- 成员内部类中不能存在任何static的变量和⽅法
- 成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类
静态内部类
关键字static可以修饰成员变量、⽅法、代码块,其实它还可以修饰内部类,使⽤static修饰的内部类我
们称之为静态内部类。静态内部类与⾮静态内部类之间存在⼀个最⼤的区别,我们知道⾮静态内部类在
编译完成之后会隐含地保存着⼀个引⽤,该引⽤是指向创建它的外围类,但是静态内部类却没有。没有
这个引⽤就意味着: - 静态内部类的创建是不需要依赖于外围类,可以直接创建
- 静态内部类不可以使⽤任何外围类的⾮static成员变量和⽅法,⽽内部类则都可以
继承的定义与使⽤
在Java中,继承使⽤extends关键字来实现,定义的语法如下:
class ⼦类 extends ⽗类
继承: extends //class Student extends Pereson
派生类继承了基类,继承了什么?
1.除构造函数外的其他东西
2.派生类需要帮助基类构造 super关键字//调用父类的构造函数 放在第一行
super.data//调用基类的属性
supe.fun()//调用基类的成员函数
Java只允许单继承,不允许多继承。
⼀个⼦类只能继承⼀个⽗类。
C同时继承A和B的主要⽬的是同时拥有A和B中的操作,为了实现这样的⽬的,可以采⽤多层继承的形式
完成。
class A{}
class B extends A{}
class C extends B{}
覆写:
class Person{
private String name;
private int age;
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;
}
}
class Student{
private String name;
private int age;
private String school;
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 getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
}
覆写
⼦类定义了与⽗类相同的⽅法或属性,这样的操作就称为覆写(override)
1.以后写⽅法时,99.99%的情况下建议使⽤public。
2.写属性,98%情况下建议使⽤private。
问题:如果现在⽗类⽅法使⽤private定义,⼦类中使⽤public覆写,对吗?
范例:⽗类使⽤private定义的⽅法,⼦类中使⽤public覆写
访问方式 public》protected》包访问权限(default)》default
super关键字
在进⾏覆写的操作过程之中,⼦类也可以使⽤super.⽅法()/super.属性明确调⽤⽗类中的⽅法或属性
范例:使⽤super调⽤⽗类的同名⽅法
class Person{
public void print(){
System.out.println(“1.I am father”);
}
}
class Student extends Person{
public void print(){
super.print();
System.out.println(“2.I am child”);
}
}
public class Test{
public static void main(String[] args) {
new Student().print();
}
}
范例:使⽤super调⽤⽗类属性
class Person{
public String info = “爸爸!”;
}
class Student extends Person{
public String info = “⼉⼦!” ;
public void print(){
//不找本类中的属性
System.out.println(super.info);
System.out.println(this.info);
}
}
public class Test{
public static void main(String[] args) {
new Student().print();
}
}
通过上述讲解可以发现super和this在使⽤上⾮常的相似,但是两者最⼤的区别是super是⼦类访问⽗类的操作,⽽this是本类的访问处理操作
final关键字
在Java中final被称为终结器。
使⽤final修饰类、⽅法、属性
final成员变量必须在声明的时候初始化或者在构造器中初始化,否则就会报编译错误
使⽤final定义的类不能有⼦类(String类便是使⽤final定义)
final⼀旦修饰⼀个类之后,该类的所有⽅法默认都会加上final修饰。(不包含成员变量)
使⽤final定义的变量就成为了常量,常量必须在声明时赋值,并且不能够被修改。
publc final int a = 100 ;
使⽤final修饰的变量不能再次赋值
定义常量(public static final ),常量全⽤⼤写字⺟,多个单词间以_分隔。
public static final int MAX_AGE = 120;
final所修饰的类/(方法)不能被继承 也称 密封类 //密封方法。
多态
基类引用派生类对象 并且基类和派生类有同名的覆盖(地址覆盖)
多态指的将父类对象应用于子类的特征,当父类中的某方法在子类中可能都有不同的实现,当用父类去实例化
子类并调用该方法时,只有在运行的时候才能知道调用的具体方法。
⽅法的多态性:
①⽅法的重载:同⼀个⽅法名称可以根据参数的类型或个数不同调⽤不同的⽅法体
②⽅法的覆写:同⼀个⽗类的⽅法,可能根据实例化⼦类的不同也有不同的实现。
对象的多态性【抽象类和接⼝才能体会到实际⽤处】(前提:⽅法覆写):
【⾃动,90%】①对象的向上转型:⽗类 ⽗类对象 = ⼦类实例。
【强制, 1%】②对象的向下转型:⼦类 ⼦类对象 =(⼦类)⽗类实例。
对象多态性的核⼼在于⽅法的覆写。
两个没有关系的类对象是不能够进⾏转型的,⼀定会产⽣ClassCastException。