类和对象的定义:
类:
在我们Java中具有许多基本数据类型,比如int、char、boolean等等,但如果我们需要描述一个活生生的人,这些基本数据类型显然满足不了我们的需求。
因此,java提供了一个很好的解决方法,就是将一个现实生活中的对象抽象成一个类。类是对一个实物(对象)进行描述的,主要描述这个实物(对象)具有哪些属性。比如说一个学生,如果我们要粗略的了解他,那就需要学号(int id)、姓名(String name)、年龄(int age)、行为(void action)等等。而我们的类就是用来描述像学生这一些对象的。
对象:
面向过程:
面向过程编程就是针对项目逻辑进行编程,强调一步一步进行。结果就是代码之间的耦合度过高,牵一发而动全身。
面向对象:
面向对象则是把面向过程的代码进行抽象,是模块化编程。好处就是模块之间相互独立,可以在原有的代码之上进行继承操作,更加方便,利于使用。
如果说类是一张设计图纸,那么对象就是根据设计图纸创造出来的一个具体的实物。比如说印在纸上的印子(对象)是通过印章(类)印出来的,它两的关系就是类和对象的关系。
例1:定义一个学生类:
public class Student {
public int id;
public String name;
public int age;
public void action() {
System.out.println(name + "去学习");
};
}
例2:创建一个学生类的对象:
public class test {
public static void main(String[] args) {
//类名 对象名 = new 类名();
Student s = new Student();
//同一个类可以创建多个实例
Student s2 = new Student();
}
}
创建完之后你就可以通过对象来做一些事情
public class test {
public static void main(String[] args) {
//类名 对象名 = new 类名();
Student s = new Student();
s.name = "张三";//给这个学生命名
s.action();//执行学生的行为
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/dd0a4f41fd463d575e6e69e1d69e14b7.png)
新建对象时的一些注意事项:
public class test {
public static void main(String[] args) {
//注意事项
//1.
Student student1 = new Student();
Student student2 = new Student();
student1 = student2;//不能这样指向!这样表示student1的引用指向了student2引用的指向
//2.
Student student3 = new Student();
student3 = new Student();
student3 = new Student();
student3 = new Student();
//这样子也只会指向一个对象
}
}
this指针:
定义:
this引用指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问。
this指针只能引用当前对象,不能引用其他对象。
public class Student {
public int id;
public String name;
public int age;
public void setData (int id, String name, int age) {
id = id;
name = name;
age = age;
}
}
在以上这种情况下,我们该如何知道id、name、age哪个对应着哪个呢?是成员对象里的还是传参的参数呢?
public class Student {
public int id;
public String name;
public int age;
public void setData (int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
}
那么在这时我们加上this指针就可以清楚的了解到前面的变量是属于当前对象的,后面的变量是属于传过来的参数的。
this是“成员方法”第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法对象的引用传递给该成员方法,this负责来接收。
public class Student {
public int id;
public String name;
public int age;
public void setData (Student this, int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/8283e68301a519fd7708652b4ecc0af4.png)
构造方法:
构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。
在Java中如果你没有重写构造方法,那么Java会自动给你提供一个构造方法。形如
![](https://i-blog.csdnimg.cn/blog_migrate/3b86772f17511909109c196670ef1c45.png)
如果你自己写了一个构造方法,那么编译器是不会再给你提供构造方法的。
构造方法是可以重载的。
有参构造:
![](https://i-blog.csdnimg.cn/blog_migrate/68b569ad5bf4a610a28980516927f81f.png)
无参构造:
![](https://i-blog.csdnimg.cn/blog_migrate/aeb6c4a0d8cfda53b65e9e646ff07831.png)
我们还可以用this()来进行简化:
this()函数必须放在第一行!!
![](https://i-blog.csdnimg.cn/blog_migrate/345b08aa92a26f56f57b014b09016b7a.png)
不过this()不能有环
![](https://i-blog.csdnimg.cn/blog_migrate/b1656f642985c23deb815729be205449.png)
初始化:
有参构造的初始化:
public static void main(String[] args) {
Student student = new Student(2, "李四", 20);
System.out.println(student.id + " " + student.name + " " + student.age);
}
![](https://i-blog.csdnimg.cn/blog_migrate/d3a72b57aa3df6f3e0711cd588202542.png)
无参构造的初始化:
public static void main(String[] args) {
Student student = new Student();
System.out.println(student.id + " " + student.name + " " + student.age);
}
![](https://i-blog.csdnimg.cn/blog_migrate/78fd89a49da6ba768f0022c3da847572.png)
就地初始化:
public class Student {
public int id = 1;
public String name = "张三";
public int age = 19;
public Student(int id, String name, int age) {
}
public Student() {
}
}
局部变量在使用时必须要先初始化,而成员变量在使用时可以不初始化,因为Java在创建一个成员变量时会做以下事情:
先查看一下该类有没有被加载过。
给创建的对象分配空间。
处理并发安全问题(比如多个线程申请对象,JVM要保证给所有对象分配空间)。
初始化所分配的空间(给对象的成员对象赋予默认值)。
![](https://i-blog.csdnimg.cn/blog_migrate/7037a5ad3a75716e4d979039e8bcd821.png)
设置对象头信息。
调用构造方法。
封装:
面向对象有三大基础特性:封装、继承、多态。
封装的定义:
封装就是将数据和对数据的一些操作进行有机融合,隐藏对象的属性和实现细节,仅公开一些对外的接口来和对象进行交互。
就像电脑一样,在电脑中,实际工作的是CPU、GPU、硬盘等硬件,然而我们在使用电脑时都是用鼠标、键盘、usb接口来对电脑进行操作。
封装提高了代码的复用性,便于调用者的使用,提高了安全性。
包:
包的定义:
包就是将多个不同的类、接口组合在一起进行组织管理的集合。(类似一个文件夹)
在一个工程中允许存在相同名称的类,只要处在不同的包中即可。
包的导入:
我们可以用import语句来导入包:
import java.util.Scanner;
//需要java.util里的其他类可以这样写:
//import java.util.*;
//不过我们更建议第一行的方法,因为不容易出现歧义
//比如java.util.*和java.sql.*里都含有Date类,此时就会报错
//我们还可以导入包中的静态方法或者静态类
import static java.lang.Math.*;
//此时在使用的时候会更加方便
double x = 30;
double y = 40;
// 静态导入的方式写起来更方便一些.
// double result = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
double result = sqrt(pow(x, 2) + pow(y, 2));
也可以在创建对象或者调用方法的时候导入包
//创建对象时
java.util.Scanner sc = new java.util.Scanner(System.in);
//使用方法时
int[] arr = {1,2,3,4,5};
System.out.println(java.util.Arrays.toString(arr));
自定义包:
![](https://i-blog.csdnimg.cn/blog_migrate/dd14fcbc8c7f3c1dda3abd322ffd4739.png)
我们在src中new一个包出来。
一般企业的命名规则是他们的域名倒过来命名的,比如我的域名是demo1.feng.com
那么我命名的时候就可以com.feng.demo1
![](https://i-blog.csdnimg.cn/blog_migrate/aadbf6c95ff4a8097c1681290531d13f.png)
D:\****\src\com\demo1\feng创建完成我们就得到这样的文件地址
然后我们就可以在包中写我们的类或接口啦。
![](https://i-blog.csdnimg.cn/blog_migrate/7ca63b11a1a2f877e9edaed45f2eaa11.png)
访问限定符:
访问限定符规定了类或字段的 被访问权限(在类外可以被使用/在类外不可以被使用)。
常用的限定符有以下几种:
![](https://i-blog.csdnimg.cn/blog_migrate/f05140bfd0154c2ab43ce8e2c373efa8.png)
static:
定义:
虽然说static是静态的意思,但是它实际上与它的字面意思关系不大。
在类中,被static修饰的成员变量称为类变量,它与类的生命周期一致,在内存中只加载一次,因此只存在一份,它不属于某个对象,是所有对象都可以修改、访问的。
static的作用:
方便我们直接使用类来访问变量或调用方法,不用创建对象。只要类被加载了,就可以通过类名来调用。static可以用来修饰成员方法、成员变量,还可以在类中编写static代码块来优化程序性能。
静态成员变量的特性:
不属于某个具体的对象,是类的属性,是所有对象共享的,不存储在某个对象的空间中。
既可以通过对象访问,也可以通过类名访问,不过更加推荐用类名访问。
类变量存储在方法区中。
随着类的加载而创建,随着类的卸载而销毁, 生命周期伴随着类的一生。
class Student {
private String name;
private int age;
public static String classroom = "306";//static修饰的成员变量
//private static String classroom = "306";//private修饰的成员变量
//不能在类外被直接调用!!
}
public class Demo1 {
public static void main(String[] args) {
System.out.println(Student.classroom);//可以用类名直接调用
Student student = new Student();
System.out.println(student.classroom);//也可以用对象直接调用
//不过不推荐这种写法,多此一举!
}
}
静态成员的初始化:
就地初始化
静态代码块初始化
静态方法初始化
private static String classroom = "306";//就地初始化
//classroom = "308";编译错误,实例代码块不能初始化静态成员变量
static {//静态代码块初始化
classroom = "308";
}
public static void setClassroom(String name) {//静态方法初始化
classroom = name;
}
静态成员初始化会在类加载的时候进行初始化,也就是程序启动的时候进行初始化。
首次创建类对象、访问类的静态成员(变量或方法)会引发类加载。
顺序优先级:静态成员变量 = 静态代码块 > 非静态成员变量 = 非静态代码块 > 构造函数
静态方法的特性:
静态方法也叫类方法,而对象方法也称为实例方法或非静态方法。
静态方法不属于某个具体的对象,是类的属性,是所有对象共享的,不存储在某个对象的空间中。
既可以通过对象访问,也可以通过类名访问,不过更加推荐用类名访问。
如果我们的静态成员变量被private与static 修饰,
![](https://i-blog.csdnimg.cn/blog_migrate/b2bf8ffa2a00bb158f4a98fd0e16aa94.png)
且我们在类外需要获取这个静态成员变量,那我们可以借助静态方法来实现:
class Student {
private String name;
private int age;
private static String classroom = "306";//private、static修饰的成员变量
public static String getClassroom() {//静态方法
return classroom;
}
}
public class Demo1 {
public static void main(String[] args) {
System.out.println(Student.getClassroom());//可以用类名直接调用
Student student = new Student();
System.out.println(student.getClassroom());//也可以用对象直接调用
//不过不推荐这种写法,多此一举!
}
}
3.在静态方法中不能调用非静态的成员变量。
![](https://i-blog.csdnimg.cn/blog_migrate/5e3ccaf290f54f9fce241b82d6a2a95d.png)
4.静态方法中不能调用非静态方法。
![](https://i-blog.csdnimg.cn/blog_migrate/0275e734521e3701815f7bd4a4f8db4d.png)
5.静态方法不能重写,无法用来实现多态(下一篇咱们细说)
代码块:
1.普通代码块:
public void goToClassroom() {
System.out.println("去上课");
}//普通代码块:定义在方法里的代码块
2.构造代码块(实例代码块):
构造代码块只有在创建对象的时候才会执行,每创建一个对象,执行一次。
class Student {
private String name;
private int age;
{
name = "张三";
age = 15;
//classroom = "308";编译错误,实例代码块不能初始化静态成员变量!!
}//构造代码块:一般用来初始化实例成员变量
}
3.静态代码块:
静态代码块无论创建多少个对象只会执行一次。
class Student {
private String name;
private static String classroom = "306";//就地初始化
static {
classroom = "308";
getClassroom();
//name = "张三"; 编译错误:静态代码块不可初始化实例成员变量!!
}//静态代码块:一般用于初始化静态成员变量,也可以调用静态方法。
public static String getClassroom() {//静态方法
return classroom;
}
}
代码块的执行顺序:
优先静态代码块执行(只执行一次!!),然后到实例化代码块,最后构造函数执行。
class Student {
private String name;
private int age;
private static String classroom;
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();
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/b94399e386c8c47e9d980cc4ec19d0b0.png)
内部类
内部类就是将一个类定义在另一个类或者方法的内部。
1.实例内部类
class A {
private int a;
private int b;
private int c;
a = 100;//编译错误,不能再变量定义阶段修改变量值!!!
public class B {//这个B类称为实例内部类
int c;
void change() {
a = 100;
b = 200;//可以在内部类访问外部类的成员变量
c = 300;//如果有同名,优先访问自己的(内部类)的成员变量
this.c = 400;//如果要访问外部类的同名成员变量,要加this
}
public B() {
System.out.println("内部类B的构造函数");
}
}
public A() {
System.out.println("外部类A的构造函数");
}
}
public class Demo2 {
public static void main(String[] args) {
A.B ab = new A().new B();//实例化内部类
}
}
构造顺序:先A后B
![](https://i-blog.csdnimg.cn/blog_migrate/9c1a763de7e1cf99cf81bf593b918999.png)
2.静态内部类
class A {
private int a;
static int b;
private static int c;
static void outmethod1() {
}
void outmethod2() {
}
static class C {//这个C类称为静态内部类
void method() {
//outmethod2();编译错误,静态代码块只能访问静态方法
//a = 100;编译错误,静态代码块只能访问静态成员变量
b = 200;
c = 200;//静态代码块能够访问静态成员变量
outmethod1();//静态代码块能够访问静态成员方法
}
}
}
public class Demo2 {
public static void main(String[] args) {
A.C ab = new A.C();//创建静态内部类的时候不用先创建外部类
}
}
3.局部内部类
class A {
void method() {
class D {//这个D类称为局部内部类
//局部内部类不能被public、static等访问限定符修饰
//局部内部类只能再方法体内部调用
}
}
}
对象的打印:
如果不重写toString方法
class Person {
private String name = "张三";
private int age = 30;
}
public class Demo3 {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person);
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/c64d35cd095a89c1a16ef0cb49fb2441.png)
打印的是类名+地址
重写toString方法之后就可以打印我们想要看到的信息啦:
class Person {
private String name = "张三";
private int age = 30;
@Override
public String toString() {//重写toString方法
return "[" + this.name + ", " + this.age + "]";
}
}
public class Demo3 {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person);
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/e7907e015d35000c48491a4ef25c6609.png)
写这种内功心法的博客总是耗费我很多时间,不过基础十分重要!时间花的是值得的,大家要多多加油巩固基础哦。