对象
概述
Java是一种面向对象的高级编程语言。
三大特征:封装,继承,多态
面向对象最重要的两个概念:类和对象
- 类:相同事物共同特征的描述。类只是学术上的一个概念并非真实存在的,只能描述一类事物
- 对象:是真实存在的实例, 实例==对象,对象是类的实例化
- 结论:有了类和对象就可以描述万千世界所有的事物。 必须先有类才能有对象
类
定义
定义格式
修饰符 class 类名{
}
- 类名的首字母建议大写,满足驼峰模式,比如 StudentNameCode
- 一个 Java 代码中可以定义多个类,按照规范一个 Java 文件一个类
- 一个 Java 代码文件中,只能有一个类是 public 修饰,public修饰的类名必须成为当前Java代码的文件名称
类中的成分:有且仅有五大成分
修饰符 class 类名{
1.成员变量(Field): 描述类或者对象的属性信息的。
2.成员方法(Method): 描述类或者对象的行为信息的。
3.构造器(Constructor): 初始化一个对象返回。
4.代码块
5.内部类
}
类中有且仅有这五种成分,否则代码报错!
public class ClassDemo {
System.out.println(1);//报错
}
构造器
构造器格式:
修饰符 类名(形参列表){
}
作用:初始化类的一个对象返回
分类:无参数构造器,有参数构造器
注意:一个类默认自带一个无参数构造器,写了有参数构造器默认的无参数构造器就消失,还需要用无参数构造器就要重新写
构造器初始化对象的格式:类名 对象名称 = new 构造器
- 无参数构造器的作用:初始化一个类的对象(使用对象的默认值初始化)返回
- 有参数构造器的作用:初始化一个类的对象(可以在初始化对象的时候为对象赋值)返回
包
包:分门别类的管理各种不同的技术,便于管理技术,扩展技术,阅读技术
定义包的格式:package 包名,必须放在类名的最上面
导包格式:import 包名.类名
相同包下的类可以直接访问;不同包下的类必须导包才可以使用
封装
封装的哲学思维:合理隐藏,合理暴露
封装最初的目的:提高代码的安全性和复用性,组件化
封装的步骤:
- 成员变量应该私有,用 private 修饰,只能在本类中直接访问
- 提供成套的 getter 和 setter 方法暴露成员变量的取值和赋值
使用 private 修饰成员变量的原因:实现数据封装,不想让别人使用修改你的数据,比较安全
this
this 关键字的作用:
- this 关键字代表了当前对象的引用
- this 出现在方法中:哪个对象调用这个方法 this 就代表谁
- this 可以出现在构造器中:代表构造器正在初始化的那个对象
- this 可以区分变量是访问的成员变量还是局部变量
static
基本介绍
Java 是通过成员变量是否有 static 修饰来区分是类的还是属于对象的。
static 静态修饰的成员(方法和成员变量)属于类本身的。
按照有无 static 修饰,成员变量和方法可以分为:
-
成员变量:
- 静态成员变量(类变量):static 修饰的成员变量,属于类本身,与类一起加载一次,只有一个,直接用类名访问即可
- 实例成员变量:无 static 修饰的成员变量,属于类的每个对象的,与类的对象一起加载,对象有多少个,实例成员变量就加载多少个,必须用类的对象来访问
-
成员方法:
- 静态方法:有 static 修饰的成员方法称为静态方法也叫类方法,属于类本身的,直接用类名访问即可
- 实例方法:无 static 修饰的成员方法称为实例方法,属于类的每个对象的,必须用类的对象来访问
static用法
成员变量的访问语法:
-
静态成员变量:只有一份可以被类和类的对象共享访问
- 类名.静态成员变量(同一个类中访问静态成员变量可以省略类名不写)
- 对象.静态成员变量(不推荐)
-
实例成员变量:
- 对象.实例成员变量(先创建对象)
成员方法的访问语法:
-
静态方法:有 static 修饰,属于类
- 类名.静态方法(同一个类中访问静态成员可以省略类名不写)
- 对象.静态方法(不推荐,参考 JVM → 运行机制 → 方法调用)
-
实例方法:无 static 修饰,属于对象
- 对象.实例方法
public class Student { // 1.静态方法:有static修饰,属于类,直接用类名访问即可! public static void inAddr(){ } // 2.实例方法:无static修饰,属于对象,必须用对象访问! public void eat(){} public static void main(String[] args) { // a.类名.静态方法 Student.inAddr(); inAddr(); // b.对象.实例方法 // Student.eat(); // 报错了! Student zbj = new Student(); zbj.eat(); } }
两个问题
内存问题:
-
栈内存存放 main 方法和地址
-
堆内存存放对象和变量
-
方法区存放 class 和静态变量(jdk8 以后移入堆)
访问问题:
- 实例方法是否可以直接访问实例成员变量?可以的,因为它们都属于对象
- 实例方法是否可以直接访问静态成员变量?可以的,静态成员变量可以被共享访问
- 实例方法是否可以直接访问实例方法? 可以的,实例方法和实例方法都属于对象
- 实例方法是否可以直接访问静态方法?可以的,静态方法可以被共享访问
- 静态方法是否可以直接访问实例变量? 不可以的,实例变量必须用对象访问!!
- 静态方法是否可以直接访问静态变量? 可以的,静态成员变量可以被共享访问。
- 静态方法是否可以直接访问实例方法? 不可以的,实例方法必须用对象访问!!
- 静态方法是否可以直接访问静态方法?可以的,静态方法可以被共享访问!!
继承
基本介绍
继承是 Java 中一般到特殊的关系,是一种子类到父类的关系
- 被继承的类称为:父类/超类。
- 继承父类的类称为:子类。
继承的作用:
- 提高代码的复用,相同代码可以定义在父类中
- 子类继承父类,可以直接使用父类这些代码(相同代码重复利用)
- 子类得到父类的属性(成员变量)和行为(方法),还可以定义自己的功能,子类更强大
继承的特点:
- 子类的全部构造器默认先访问父类的无参数构造器,再执行自己的构造器
- 单继承:一个类只能继承一个直接父类
- 多层继承:一个类可以间接继承多个父类(家谱)
- 一个类可以有多个子类
- 一个类要么默认继承了 Object 类,要么间接继承了 Object 类,Object 类是 Java 中的祖宗类
继承的格式:
子类 extends 父类{
}
子类不能继承父类的东西:
- 子类不能继承父类的构造器,子类有自己的构造器
- 子类是不能可以继承父类的私有成员的,可以反射暴力去访问继承自父类的私有成员
- 子类是不能继承父类的静态成员的,子类只是可以访问父类的静态成员,父类静态成员只有一份可以被子类共享访问,共享并非继承
public class ExtendsDemo {
public static void main(String[] args) {
Cat c = new Cat();
// c.run();
Cat.test();
System.out.println(Cat.schoolName);
}
}
class Cat extends Animal{
}
class Animal{
public static String schoolName ="seazean";
public static void test(){}
private void run(){}
}
变量访问
继承后成员变量的访问特点:就近原则,子类有找子类,子类没有找父类,父类没有就报错
如果要申明访问父类的成员变量可以使用:super.父类成员变量,super指父类引用
public class ExtendsDemo {
public static void wmain(String[] args) {
Wolf w = new Wolf();w
w.showName();
}
}
class Wolf extends Animal{
private String name = "子类狼";
public void showName(){
String name = "局部名称";
System.out.println(name); // 局部name
System.out.println(this.name); // 子类对象的name
System.out.println(super.name); // 父类的
System.out.println(name1); // 父类的
//System.out.println(name2); // 报错。子类父类都没有
}
}
class Animal{
public String name = "父类动物名称";
public String name1 = "父类";
}
方法访问
子类继承了父类就得到了父类的方法,可以直接调用,受权限修饰符的限制,也可以重写方法
方法重写:子类重写一个与父类申明一样的方法来覆盖父类的该方法
方法重写的校验注解:@Override
- 方法加了这个注解,那就必须是成功重写父类的方法,否则报错
- @Override 优势:可读性好,安全,优雅
子类可以扩展父类的功能,但不能改变父类原有的功能,重写有以下三个限制:
- 子类方法的访问权限必须大于等于父类方法
- 子类方法的返回类型必须是父类方法返回类型或为其子类型
- 子类方法抛出的异常类型必须是父类抛出异常类型或为其子类型
继承中的隐藏问题:
- 子类和父类方法都是静态的,那么子类中的方法会隐藏父类中的方法
- 在子类中可以定义和父类成员变量同名的成员变量,此时子类的成员变量隐藏了父类的成员变量,在创建对象为对象分配内存的过程中,隐藏变量依然会被分配内存
public class ExtendsDemo {
public static void main(String[] args) {
Wolf w = new Wolf();
w.run();
}
}
class Wolf extends Animal{
@Override
public void run(){}//
}
class Animal{
public void run(){}
}
面试问题
-
为什么子类构造器会先调用父类构造器?
- 子类的构造器的第一行默认 super() 调用父类的无参数构造器,写不写都存在
- 子类继承父类,子类就得到了父类的属性和行为。调用子类构造器初始化子类对象数据时,必须先调用父类构造器初始化继承自父类的属性和行为
- 参考 JVM → 类加载 → 对象创建
class Animal{ public Animal(){ System.out.println("==父类Animal的无参数构造器=="); } } class Tiger extends Animal{ public Tiger(){ super(); // 默认存在的,根据参数去匹配调用父类的构造器。 System.out.println("==子类Tiger的无参数构造器=="); } public Tiger(String name){ //super(); 默认存在的,根据参数去匹配调用父类的构造器。 System.out.println("==子类Tiger的有参数构造器=="); } } -
为什么 Java 是单继承的?
答:反证法,假如 Java 可以多继承,请看如下代码:
class A{ public void test(){ System.out.println("A"); } } class B{ public void test(){ System.out.println("B"); } } class C extends A , B { public static void main(String[] args){ C c = new C(); c.test(); // 出现了类的二义性!所以Java不能多继承!! } }
super
继承后 super 调用父类构造器,父类构造器初始化继承自父类的数据。
总结与拓展:
- this 代表了当前对象的引用(继承中指代子类对象):this.子类成员变量、this.子类成员方法、this(...)可以根据参数匹配访问本类其他构造器。
- super 代表了父类对象的引用(继承中指代了父类对象空间):super.父类成员变量、super.父类的成员方法、super(...)可以根据参数匹配访问父类的构造器
注意:
- this(...) 借用本类其他构造器,super(...) 调用父类的构造器。
- this(...) 或 super(...) 必须放在构造器的第一行,否则报错!
- this(...) 和 super(...) 不能同时出现在构造器中,因为构造函数必须出现在第一行上,只能选择一个。
public class ThisDemo {
public static void main(String[] args) {
// 需求:希望如果不写学校默认就是”张三“!
Student s1 = new Student("天蓬元帅", 1000 );
Student s2 = new Student("齐天大圣", 2000, "清华大学" );
}
}
class Study extends Student {
public Study(String name, int age, String schoolName) {
super(name , age , schoolName) ;
// 根据参数匹配调用父类构造器
}
}
class Student{
private String name ;
private int age ;
private String schoolName ;
public Student() {
}
public Student(String name , int age){
// 借用兄弟构造器的功能!
this(name , age , "张三");
}
public Student(String name, int age, String schoolName) {
this.name = name;
this.age = age;
this.schoolName = schoolName;
}
// .......get + set
}
final
基本介绍
final 用于修饰:类,方法,变量
- final 修饰类,类不能被继承了,类中的方法和变量可以使用
- final 可以修饰方法,方法就不能被重写
- final 修饰变量总规则:变量有且仅能被赋值一次
面试题:final 和 abstract 的关系是互斥关系,不能同时修饰类或者同时修饰方法!
修饰变量
静态变量
final 修饰静态成员变量,变量变成了常量
常量:有 public static final 修饰,名称字母全部大写,多个单词用下划线连接。
final 修饰静态成员变量可以在哪些地方赋值:
-
定义的时候赋值一次
-
可以在静态代码块中赋值一次
public class FinalDemo {
//常量:public static final修饰,名称字母全部大写,下划线连接。
public static final String SCHOOL_NAME = "张三" ;
public static final String SCHOOL_NAME1;
static{
//SCHOOL_NAME = "java";//报错
SCHOOL_NAME1 = "张三1";
//SCHOOL_NAME1 = "张三2"; // 报错,第二次赋值!
}
}
实例变量
final 修饰变量的总规则:有且仅能被赋值一次
final 修饰实例成员变量可以在哪些地方赋值 1 次:
- 定义的时候赋值一次
- 可以在实例代码块中赋值一次
- 可以在每个构造器中赋值一次
public class FinalDemo {
private final String name = "张三" ;
private final String name1;
private final String name2;
{
// 可以在实例代码块中赋值一次。
name1 = "张三1";
}
//构造器赋值一次
public FinalDemo(){
name2 = "张三2";
}
public FinalDemo(String a){
name2 = "张三2";
}
public static void main(String[] args) {
FinalDemo f1 = new FinalDemo();
//f1.name = "张三1"; // 第二次赋值 报错!
}
}
更多文章请关注《万象专栏》
转载请注明出处:https://www.wanxiangsucai.com/read/cv15898