面向对象编程系列五
` 提示:本文主要叙述了Java中类和对象的相关知识语法
文章目录
提示:以下是本篇文章正文内容,下面案例可供参考
一、类和对象
Java是一门面向对象的编程语言,在Java中一切皆对象,不关注过程。
语法
class 类名{
成员属性/成员变量;
成员方法;
}
面向对象的三大特性:封装 继承 多态
封装:将数据和操作数据的方法进行有机的结合,隐藏对象的属性和具体实现细节,仅对外公开接口来和其他对象进行交互。
定义类
下面定义一个学生类进行展示
注意:1.类名的定义采用大驼峰的形式
2.成员变量前先统一写为public 涉及权限问题,后续做出解释
3.此处的方法暂时不写static,涉及静态成员方法和非静态成员方法
后续做出解释
4.一般来说一个.Java文件中只有一个类,更加直观。
5.一个.Java文件中有且只能有一个类可以被public修饰 public class
+类名。
class Student{
public String name;
public int age;
public void study(){
System.out.println(name + "正在认真学习");
}
public void play(){
System.out.println("年龄为:"+ age + "姓名为:"
+ name + "正在打篮球");
}
}
类实例化对象
一个类可以通过new关键字实例化多个对象。
通过类Student实例化出student1 student2和student3三个对象
输出结果展示:
Student@1b6d3586
Student@4554617c
Student@74a14482
这里Student可以理解为一个引用类型
public class Test {
public static void main(String[] args) {
Student student1 = new Student();
Student student2 = new Student();
Student student3 = new Student();
System.out.println(student1);
System.out.println(student2);
System.out.println(student3);
}
}
通过对象引用类中成员变量和成员方法
下面展示一些 内联代码片
。
输出结果:
小郭子正在认真学习
年龄为:20 姓名为:小郭子 正在打篮球
小灰灰正在认真学习
年龄为:22 姓名为:小灰灰 正在打篮球
小结:类通过new关键字可以实例化多个对象
通过对象.xxxx可以访问类中的成员变量或者成员方法。
public static void main(String[] args) {
Student student1 = new Student();
Student student2 = new Student();
student1.name = "小郭子";
student1.age = 20;
student1.study();
student1.play();
student2.name = "小灰灰";
student2.age = 22;
student2.study();
student2.play();
在堆和栈上示意图展示
另外介绍成员变量的默认初始化:
1.成员变量与局部变量的区别:
局部变量定义在方法内部,成员变量定义在类的内部和方法的外部,局部变量必须进行初始化,成员变量可以不初始化。
生命周期:成员变量从对象创建后开始存在知道对象销毁
局部变量进入方法创建,出方法销毁
2.不进行赋值操作时,如果是引用类型,则默认为null,如果是int float默认为0, 如果是boolean类型默认为false, 如果是char类型默认为\u0000。
3.当这个引用被赋值为null时候,这个引用不再指向任何对象
4.如果两个对象建立 =操作 例如:student1 = student2,那么此时student2指向student1所指向的对象,即一个对象被多个引用所指
5.一个引用只能指向一个对象,不可以指向多个对象!!!
二、this引用
注意:this不能调用静态方法和属性,后续会进行解释。
表示当前对象的引用
输出结果:
年龄为:20 姓名为:灰太狼 正在打篮球
年龄为:8 姓名为:小灰灰 正在打篮球
this表示当前对象的引用,例如student1调用Student类中的方法,向
其中传参 当前对象就是方法.前面的对象,this.name就是对当前
student1的name和age时进行赋值
等到student2调用该方法时又对student2在栈上的name和age进行赋值
public void setStudent(String name,int age){
this.name = name;
this.age = age;
}
public static void main(String[] args) {
Student student1 = new Student();
student1.setStudent("灰太狼",20);
student1.play();
Student student2 = new Student();
student2.setStudent("小灰灰",8);
student2.play();
}
构造方法
构造方法是一种特殊的方法
1.方法名和类名相同,可以带参也可以不带参数。
2.如果程序员没有写构造方法,那么Java会提供默认提供一个不带参数的构造方法。
3.如果写了构造方法,无论几个参数,Java都不会再提供不带参数的构造方法了。
public + 类名(){
...........
}
(!!!注意不要在public后面加void)
右键generate -->constructor---->可以快速生成任意个数的带参或者不带参的构造方法。
深度理解关键字new在创建对象时的步骤
1.为对象分配内存空间
2.调用合适的构造方法
下面展示一些 内联代码片
。
输出结果:
调用了不带参数的构造方法,此方法执行完后,一个对象创建完成
==========
调用了不带参数的构造方法,此方法执行完后,一个对象创建完成
public Student(){
System.out.println("调用了不带参数的构造方法,此方法
执行完后,一个对象创建完成");
}
public static void main(String[] args) {
Student student1 = new Student();
System.out.println("==========");
Student student2 = new Student();
}
this访问其他构造方法
注意:
1.必须放在第一行
2.只能在构造方法内部才能使用
下面展示一些 内联代码片
。
输出结果:
调用了不带参数的构造方法
回到带参数的构造方法
年龄为:25 姓名为:大头 正在打篮球
public Student(){
System.out.println("调用了不带参数的构造方法");
}
public Student(String name, int age) {
this();
System.out.println("回到带参数的构造方法");
this.name = name;
this.age = age;
}
public static void main(String[] args) {
Student student1 = new Student("大头",25);
student1.play();
}
this访问其他对象的其他成员方法
输出结果:
调用了当前对象的其他成员方法
回到带参数的构造方法
年龄为:25 姓名为:大头 正在打篮球
public void func(){
System.out.println("调用了当前对象的其他成员方法");
}
public Student(String name, int age) {
this.func();
System.out.println("回到带参数的构造方法");
this.name = name;
this.age = age;
}
public static void main(String[] args) {
Student student1 = new Student("大头",25);
student1.play();
}
三、访问修饰限定符---->权限
1.同一个包中的同一个类
2.同一个包中的不同类
3.不同包中的子类(涉及继承的知识)
4.不同包中的非子类
private:1 也就可以理解为只能在当前类中使用
默认权限(default):1 2 可以理解为只能在同一个包中使用
protected :1 2 3 可以理解为不同包中子类内都可以任何时候
public :1 2 3 4 可以理解为公开权限,即在任何情况下不同类或者不同包都可以使用
出现如下情况时候,可以进行这样修改 使得代码快起来更加规整简洁。
当成员变量被private修饰的时候 其他类无法直接得知可以通过get和set方法进行获取和修改。
静态成员变量、静态成员方法、代码块
成员变量的两种分类
1.静态成员变量/类成员变量
2.非静态成员变量
注意:静态成员变量不能通过对象的引用来访问,但是可以通过类名.xxxx直接访问,因此这也是它为什么叫做类成员变量的原因。
输出结果:
123班
public static String classroom = "123班";
System.out.println(Student.classroom);
成员方法的两种分类
1.静态成员方法/类方法
2.非静态成员方法
被static修饰的方法成为静态方法/类方法
静态方法使用需要注意以下三点
代码块
成员变量初始化
1.默认值初始化
2.直接赋值
public static String classroom = "123班";
3.通过get和set方法进行赋值
public static String getClassroom() {
return classroom;
}
public static void setClassroom(String classroom) {
Student.classroom = classroom;
}
4.通过构造方法进行赋值
public void setStudent(String name,int age){
this.name = name;
this.age = age;
}
新学习的一种方式就是通过代码块进行赋值
首先先来看一下代码块的分类
1.普通代码块
2.非静态代码块/实例化代码块/构造代码块
用来初始化非静态成员变量
3.静态代码块 用来初始化静态成员变量
4.同步代码块 (将在ee初阶中多线程部分进行详细讲解)
下面展示一些 内联代码片
。
非静态代码块的执行顺序
输出结果:
非静态代码块/实例代码块/构造代码块--->初始化非静态成员变量
不带参数的构造方法
曹操
=======
非静态代码块/实例代码块/构造代码块--->初始化非静态成员变量
不带参数的构造方法
曹操
class Student{
public String name = "飞飞战神x";
public int age;
{
name = "曹操";
System.out.println("非静态代码块/实例代码块/构造代码块--->初始化非静态成员变量");
}
public Student(){
System.out.println("不带参数的构造方法");
}
!!!!!!
public static void main(String[] args) {
Student student1 = new Student();
System.out.println(student1.name);
System.out.println("=======");
Student student2 = new Student();
System.out.println(student2.name);
}
下面展示一些 内联代码片
。
输出结果:
非静态代码块/实例代码块/构造代码块--->初始化非静态成员变量
不带参数的构造方法
飞飞战神x
=======
非静态代码块/实例代码块/构造代码块--->初始化非静态成员变量
不带参数的构造方法
飞飞战神x
class Student{
public int age;
{
name = "曹操";
System.out.println("非静态代码块/实例代码块/构造代码块--->初始化非静态成员变量");
public String name = "飞飞战神x";
}
public Student(){
System.out.println("不带参数的构造方法");
}
!!!!!!
public static void main(String[] args) {
Student student1 = new Student();
System.out.println(student1.name);
System.out.println("=======");
Student student2 = new Student();
System.out.println(student2.name);
}
===========================================
Student student3 = new Student("旺财",15);
System.out.println(student3.name);
输出结果为::旺财
总结:1.如果方法和成员变量都是非静态的,则看代码执行顺序,成员变量中的赋值”飞飞战神x“和“曹操”谁在最后,则就是最后的那个值
2.new实例化对象时会调用合适的构造方法,再调用构造方法之前又会先执行非静态代码块。
3.同理:根据执行顺序来看 如果调用了带参数的构造方法,那么最后的值肯定还是原来的数值 因为先执行非静态代码块再执行带参的构造方法
静态代码块的执行顺序
下面展示一些 内联代码片
。
输出结果:
静态代码块--->初始化静态成员变量
不带参数的构造方法
曹操
=======
不带参数的构造方法
曹操
public static String name = "飞飞战神x";
static {
name = "曹操";
System.out.println("静态代码块--->初始化静态成员变量");
}
public Student(){
System.out.println("不带参数的构造方法");
}
====================================
public static void main(String[] args) {
Student student1 = new Student();
System.out.println(student1.name);
System.out.println("=======");
Student student2 = new Student();
System.out.println(student2.name);
此处student2的值仍为曹操是因为随着类的加载静态代码块被执行时候方法区内存放静态成员变量的飞飞战神x改为了曹操所以实例化对象时候,即使静态代码块没有执行,name名字仍然为曹操。
调换public static String name 和static{}的位置
下面展示一些 内联代码片
。
输出结果:
静态代码块--->初始化静态成员变量
不带参数的构造方法
飞飞战神x
=======
不带参数的构造方法
飞飞战神x
static {
name = "曹操";
System.out.println("静态代码块--->初始化静态成员变量");
}
public static String name = "飞飞战神x";
public Student(){
System.out.println("不带参数的构造方法");
}
====================================
public static void main(String[] args) {
Student student1 = new Student();
System.out.println(student1.name);
System.out.println("=======");
Student student2 = new Student();
System.out.println(student2.name);
总结:1.放成员变量初始化和代码块都是静态时,看哪个代码在后面 谁在最后面 就是谁的值
二者相结合
输出结果:
静态代码块---->初始化静态成员变量
非静态代码块/实例化代码块/构造代码块---->初始非静态成员变量
不带参数的构造方法
========
非静态代码块/实例化代码块/构造代码块---->初始非静态成员变量
不带参数的构造方法
class Student{
public String name;
public int age;
static{
System.out.println("静态代码块---->初始化静态成员变量");
}
{
System.out.println("非静态代码块/实例化代码
块/构造代码块---->初始非静态成员变量");
}
public Student(){
System.out.println("不带参数的构造方法");
}
}
public class Test {
public static void main(String[] args) {
Student student1 = new Student();
System.out.println("========");
Student student2 = new Student();
}
}
总结:new关键字实例化对象时候,执行顺序为被static修饰的静态代码块随类的加载只被执行一次,然后执行非静态代码块,最后再执行构造方法。
附加:JDK8前后方法区的变化
被static修饰的静态成员变量
1.static{}代码块会修改存放在方法区的值
2.static{}后如果再有public static String name =xxx
也会改变方法区的值
3.需要注意的是存放静态成员变量的区域在jdk8前后是有变化的
jdk8之前 常量池和静态成员变量是存放在方法区的,但是在jdk8之后用“元空间’代替了”永久代“,元空间就是本地内存,永久代中的数据也进行了迁移,其中静态成员变量和常量池就去往了堆中。