文章目录
听说你还不会面向对象,那看这篇就够了
.
类和类的实例化
类是一类对象的统称,对象就是这一类具体化的实例.
<class_name> 对象名 = new <class_name>
Student s = new Student();
成员变量
class{
public String name = "张三";//如果不设置初始值,变量就为默认值
public int age = 18;
}
方法
成员方法
用于描述一个对象的行为
public class Person {
public String name = "张三";
public int age = 30;
//成员方法
public void show() {
System.out.println("我叫" + name + ",今年" + age + "岁了");
}
这种show()方法和Person实例是相关联的,如果创建了其他实例,那么相应的show()也会发生变化.
构造方法
构造方法是类中的一种特殊的方法,使用new实例化对象时实际上就调用了该方法.
构造方法的作用就是产生对象
new 一个对象时,内部干了两件事:
- 为对象在堆中分配空间
- 调用构造方法为类中的成员变量进行赋值.
class Test {
public static void main(String[] args) {
}
}
class Student {
private String name;
private int age;
//无参构造方法
public Student() {
}
//带参构造方法
public Student(String name) {
}
}
构造方法的规则:
- 方法名与类名称相同
- 无返回值声明
- 如果没有手动构造无参构造方法,系统会自动生成无参构造方法.
- 如果已经给了带参构造方法,系统将不再生成无参构造方法.
构造方法可以重载,只是重载的参数个数不同,因为参数的类型在类中声明变量时已经确定了.
static关键字
静态变量
在定义一个类时,只是在描述某类事物的特征和行为,并没有产生具体的数据,只有通过new关键字实例对象后,系统才会为某个对象分配空间,存储各自的数据.
有时候,开发人员为了某些数据在 内存中只存在一份,例如:一个学校的学生他们都共享同一个学校名称,这时候就不必在每个对象所占的内存空间中都声明一个变量来表示学校名称,只需要在类的外部声明一个变量来让所有对象共享.
看一段程序:
public class Test1 {
public static void main(String[] args) {
Person per1 = new Person();
Person per2 = new Person();
per1.name = "小明";
per1.age = 20;
//静态变量必须通过类名类访问
Person.SchoolName = "北京大学";//北京大学
per1.show();
per2.name = "小明";
per2.age = 20;
Person.SchoolName = "南京大学";
//静态成员变量对所有对象都是共享的
per1.show();//南京大学
per2.show();
}
}
class Person {
String name;
int age;
static String SchoolName = "清华大学";
//成员方法,实例方法,也需要通过对象来访问
void show() {
System.out.println("name:" + name + "\tage:" + age + "\tSchoolName:" + SchoolName);
}
}
运行结果:
静态成员变量在JVM中存在于方法区.
首先,会调用new Person()来产生Person对象,先要有Person类才能产生Person对象,先将Person类加载到内存中,Person 的所有静态变量被加载到方法区中.
看见static关键字,本能反应,是与对象无关,静态的,表示共有的含义
当一个实例变量被static修饰时,它就表示类的属性,该类的所有对象共享这个属性,所有对象的属性值大家都一样.
总结:变量被static修饰,在JVM的方法区存储,被所有对象共享.
在java中,能否在方法一个方法内部定义一个静态变量?
回答:不行,因为方法中定义的变量是局部变量,局部变量储存在栈中,而静态变量是全局变量,是储存在方法区内部的.
既然我么要定义全部变量,让所有对象共享所以:
静态方法
如果要使用类中的成员方法,首先我们要将类实例化,再通过类的对象去访问方法,但有时我们不想创建对象又想去访问成员方法,这种情况下,我们就使用静态方法.
static修饰的方法,可以通过类名直接访问,无需创建对象,通过对象去访问.
public class Test1 {
public static void main(String[] args) {
Person.show1();
}
}
class Person {
static String SchoolName = "清华大学";
static void show1(){
System.out.println(SchoolName);
}
}
为什么main方法是一个静态方法?
因为main方法是一个程序的入口,如果它是成员方法,那它需要实例化才能访问里面的成员对象,如果连入口都没有,又如何实例化对象呢.
public static void main(String[] args) {
}
静态方法能访问成员变量和成员方法吗?
不能,成员方法必须通过对象来访问和调用.
成员方法能访问静态变量和静态方法吗?
可以,静态方法和静态变量本身可以通过类来访问,现在有了对象了,更能访问了.
普通的类能否用static修饰?
不能,类被创造出来就是为了产生对象的,如果用static修饰,产生不了对象,那么这个类就失去了作用了.
工具类方法都为静态方法?
易错点:
是的,他们都是通过类名调用的(Arrays.sort(int[] arr)).
public class Test {
static void show() {
System.out.println("猫吃鱼");
}
public static void main(String args[]) {
Test test = null;
test.show();
}
}
//输出:猫吃鱼
说明:静态成员方法可以通过类名来访问.
public class Test {
void show() {
System.out.println("猫吃鱼");
}
public static void main(String args[]) {
Test test = null;
test.show();
}
}
//运行出错:NullPointerException
成员方法只能通过对象来访问,这里并没有new出对象,只是声明了一个对象引用,所以会报错.
this关键字
- 调用当前对象的成员变量
- 调用当前对象的方法
- 调用普通的成员方法
- 调用构造方法
- 表示当前对象的引用
this关键字调用当前对象的成员变量
class Student {
public int age;//成员变量
public Student(int a) {//a是局部变量
age = a;
}
}
如果程序写成上面这样,那么程序的可读性将会变得很差.
我们将程序修改一下:
class Test {
public static void main(String[] args) {
Student s = new Student(12);
System.out.println(s.age); //输出结果为0,说明并没有赋值成功
}
}
class Student {
public int age;//成员变量
public Student(int age) {//a是局部变量
age = age;
}
}
原因:
所以我们引入了this这个关键字:
public static void main(String[] args) {
Student s = new Student(12);
System.out.println(s.age); //输出为12.
}
}
class Student {
public int age;//成员变量
public Student(int age) {//a是局部变量
this.age = age;
}
}
this关键字调用类中的方法
this关键字调用当前对象的成员方法
class ThisTest {
public static void main(String[] args) {
Student s = new Student();
s.show();
}
}
class Student {
public void show() {
//下面这两行代码是一样的,this可以写,也可以不写
// 如果不写,编译器编译程序的时候会自动生成
// this.Test();
Test();
System.out.println("Student类中的show方法");
//输出结果:
// Studnet类中的Test方法
// Student类中的show方法
}
public void Test() {
System.out.println("Studnet类中的Test方法");
}
}
this关键字调用当前对象的构造方法
class Student {
String name;
int age;
public Student() {
System.out.println("Student的无参构造方法");
}
public Student(String name) {
this(); //调用无参构造
this.name = name;
System.out.println(name);
}
public Student(String name, int age) {
this("张三"); //调用带参构造
this.name = name;
this.age = age;
System.out.println(name);
System.out.println(age);
}
}
构造方法之间可以互相调用,但是注意,不能调用形成闭环.
什么意思呢,比如上面的程序:第二个方法调用第一个方法,第三个方法调用第二个方法,第一个方法又调用第三个方法,这样就会形成死循环.
注意:this关键字调用其他构造方法,必须放在首行,负责编译器会报错.
public Student() {
System.out.println("Student的无参构造方法");
}
public Student(String name) {
this.name = name;
this(); //java: 对this的调用必须是构造器中的第一个语句
System.out.println(name);
}
this关键字表示当前对象的引用
当前的方法或属性是哪个对象调用的,this就指代哪个对象
看程序:
class ThisTest {
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student();
s1.show();//Student@14ae5a5
s2.show();//Student@7f31245a
}
}
class Student{
public void show(){
System.out.println(this);
}
}
可以看出程序分别输出了s1和s2的地址,说明了谁调用this,this就指代谁
代码块
什么是代码块?
代码块就是{…}里面的代码
代码块分类:
- 普通代码块
- 成员代码块
- 静态代码块
- 同步代码块
普通代码块
定义在方法中,使用{}括起来的代码
成员代码块
定义在类中,使用{}括起来的代码,也叫构造块
class Test {
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student();
}
}
class Student {
{
System.out.println("构造块");
}
}
class Test {
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student();
}
}
class Student {
public Student(){
System.out.println("无参构造方法");
}
{
System.out.println("构造块");
}
}
总结:构造块定义在类中,不加任何修饰,优先于构造方法的执行,有几个对象,就执行几次构造代码块.
静态代码块
1.定义在类中,使用static修饰的代码块,与对象无关,在类加载的时候运行一次,无论产生对少个对象,都只运行一次.
class Test {
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student();
}
}
class Student {
static {
System.out.println("静态代码块");
}
}
2.如果静态代码块在主类中,那么是先加载主方法呢?还是先运行静态代码块呢?
我们来实验一下:
class Test {
public static void main(String[] args) {
Student s = new Student();
}
static {
System.out.println("静态代码块1");
}
}
class Student {
static {
System.out.println("静态代码块");
}
}
3.静态代码在内存中是如何存在的呢?
前面我们说过静态代码块在类加载时才会运行一次.
匿名对象
匿名对象,顾名思义,没有名字,使用一次就销毁了,常用于测试某些功能的时候.
toString方法
我们在java程序中,如果我们打印一个对象,打印出的是这个对象的地址.
class Test {
public static void main(String[] args) {
Student s =new Student();
System.out.println(s);//Student@14ae5a5
}
}
class Student{
}
重写toString方法,我们再看.
class Test {
public static void main(String[] args) {
Student s = new Student("小明", 18);
System.out.println(s);//Student@14ae5a5
}
}
class Student {
String name;
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + "," + age;
}
}
重写toString()方法,返回的是什么类型,输出的就是什么.