一:代码块:
1)实例代码块,使用一个大括号,里面可以放一些语句和访问一些成员变量(定义在类中的代码块),也叫做构造代码块,一般用于初始化实例成员变量,当我们去new一个对象的时候,就会被执行了,可以初始化一个实例成员变量
public class TestDemo{ public String name; public int age; public static String str; { this.name="李佳伟";//初始化实例成员变量 this.age=90; } static { str="生命";//初始化静态成员变量 this.name=""//报错 } }
2)静态代码块:
static{
里面放一些字段和方法
};
在我们通过类名进行访问静态成员的时候,也会默认执行静态代码块的内容
public class TestDemo{ public static int count=10; static { count=99; } public static void main(String[] args) { System.out.println(TestDemo.count); } } //打印结果是99
package Demo; public class TestDemo{ static { count=99; } public static int count=10; public static void main(String[] args) { System.out.println(TestDemo.count); } } //打印结果是10
1)如果count没有进行初始化,那么在任何位置(定义count的位置和static代码块的位置),count的值都是static代码块的值
2)静态代码块的执行顺序>实例代码块的执行顺序,一般用于初始化静态成员变量,再进行类加在的时候就被调用了
静态代码块>实例代码块>不带参数构造方法
1)静态代码块在类加载的时候就被执行了(类加载是在对象创建之前就会被执行),所以是最早执行的
2)当我们实例化一个对象的时候,先进行执行实例代码块,在继续执行构造方法
3)实例代码块只会初始化实例的成员,静态代码块是用来初始化静态的成员变量的
4)实例代码块也不是必须要写{}的
5)父类的静态代码块>子类静态代码块>父类的实例代码块>父类构造方法>子类实例代码块>子类的构造方法
package 李佳伟;
import javax.swing.*;
import java.security.PrivateKey;
import java.util.Scanner;
import java.util.Arrays;
import java.util.Scanner;
class Person//一个类
{
public int age;
public static int count=0;
public Person()//无返回值类型声明,且必须与类名相同
{
System.out.println("我是构建方法");
}
{
System.out.println("我是示例代码块");
}
static
{
count=99;//如果都是静态的,则初始化前看一看被定义的先后顺序
this.age=18;不能进行访问,因为静态代码区不能访问实例变量,且this表示当前对象的引用
System.out.println("我是静态代码块");
}
}
public class HelloWorld {
public static void main(String[] argv)
{
Person lijiawei=new Person();//lijiawei就是一个对象,而且一个类可以面向多个对象
}
}
1)所以我们得出结论,对于静态代码快来说,程序中无论生成多少个对象,静态代码块就只会执行一次,况且是最先执行的
2)静态代码块执行完毕后,实例代码块(构造快)再去执行,最后是构造方法执行,静态成员变量是类的属性,因此是在JVM加载类的时候开辟空间并进行初始化的
3)如果一个类中包含着多个静态代码块,在进行编译代码的时候,编译器会按照定义的先后顺序依次执行
4)实例代码块只有在创建对象的时候才会执行
5)上面的重写ToString方法把对象转化成字符串被称之为序列化
6)都是静态的,那么和定义的先后顺序有关系
反序列化:将字符串转化成对象-----后面前后端进行交互的时候,讲一个字符串转化成JSON格式的数据
补充:
1)序列化最重要的作用:在传递和保存对象时,保证对象的完整性和可传递性,对象转换为有序字节流,以便在网络上传输或者保存在本地文件中
2)反序列化的最重要的作用:根据字节流中保存的对象状态及描述信息,通过反序列化重建对象。
3)核心作用就是对象状态的保存和重建,(整个过程核心点就是字节流中所保存的对象状态及描述信息)
class Person{
public static int count=0;
static{
System.out.println("我是静态代码块");
}
public static void run()
{
System.out.println("我是run方法");
}
}
System.out.println(Person.count);
//最终打印的结果是我是静态代码块,0
对于toString方法来说,在调用println方法的时候会被自动调用
JAVA的序列化和反序列化:
只有实现了Serializable或者Externalizable接口的类的对象才能被序列化为字节序列。(不是则会抛出异常)
JDK中序列化和反序列化的API: 1)java.io.ObjectInputStream:对象输入流 类的readObject()方法从输入流中读取字节序列,然后将字节序列反序列化为一个对象并返回。 2)java.io.ObjectOutputStream:对象输出流 该类的writeObject(Object obj)方法将将传入的obj对象进行序列化,把得到的字节序列写入到目标输出流中进行输出
实现序列化和反序列化的实现:
1)若Student类仅仅实现了Serializable接口,并且还定义了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),则采用以下方式进行序列化与反序列化 2)ObjectOutputStream调用Student对象的writeObject(ObjectOutputStream out)的方法进行序列化。 3)ObjectInputStream会调用Student对象的readObject(ObjectInputStream in)的方法进行反序列化
1)若Student类实现了Externalnalizable接口,且Student类必须实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,则按照以下方式进行序列化与反序列化。 2)ObjectOutputStream调用Student对象的writeExternal(ObjectOutput out))的方法进行序列化 3)ObjectInputStream会调用Student对象的readExternal(ObjectInput in)的方法进行反序列化
1)Java有很多基础类已经实现了serializable接口,比如String,Vector等。但是也有一些没有实现serializable接口的;
2)static修饰字段不能被序列化
public class TestDemo{ static class Student implements Serializable { public int age; public String name; public Student(int age,String name) { this.age=age; this.name=name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student{" + "age=" + age + ", name='" + name + '\'' + '}'; } } public static void main(String[] args) throws IOException, ClassNotFoundException { //1.序列化 File file=new File("d:/textDemo.txt"); FileOutputStream f1=new FileOutputStream(file); ObjectOutputStream outputStream=new ObjectOutputStream(f1); outputStream.writeObject(new Student(18,"hhhh")); //2反序列化 FileInputStream f2= new FileInputStream(file); ObjectInputStream inputStream= new ObjectInputStream(f2); Student student2 = (Student) inputStream.readObject(); System.out.println(student2); }
练习1:编写一个类Calculator,有两个属性num1和num2这两个数据的值,不能在定义的时候进行初始化,最后实现加减乘除四种运算
package Demo; class Calculator{ private int num1; private int num2; public void setNum1(int num1) { this.num1 = num1; } public void setNum2(int num2) { this.num2 = num2; } public int add(){ return num1+num2; } public int sub(){ return num1-num2; } public int mul(){ return num1*num2; } public double dev(){ return num1*1.0/num2; } } public class TestDemo{ public static void main(String[] args) { Calculator calculator=new Calculator(); calculator.setNum1(10); calculator.setNum2(20); System.out.println(calculator.add()); System.out.println(calculator.sub()); System.out.println(calculator.dev()); System.out.println(calculator.mul()); } }
练习2:设计交换两个变量的值,要求交换实参的值
把实参的值放到我们的堆上,有地址就好了
public class TestDemo{ public static void main(String[] args) { int a=10; int b=90; swap(a,b); System.out.println(a); System.out.println(b); } private static void swap(int a, int b) { int temp=a; a=b; b=temp; } } 无法交换
解法:交换引用中属性的值,或者说直接交换数组中的两个值
package Demo; class MyValue{ public int data; } public class TestDemo{ public static void main(String[] args) { MyValue myValue1=new MyValue(); myValue1.data=90; MyValue myValue2=new MyValue(); myValue2.data=100; swap(myValue1,myValue2); System.out.println("myValue1.data="+myValue1.data); System.out.println("MyValue2.data="+myValue2.data); } private static void swap(MyValue myValue1, MyValue myValue2) { int temp=myValue1.data; myValue1.data=myValue2.data; myValue2.data=temp; } }
包:
其实在JAVA中,引入了包,包是对类,接口等封装机制的体现,是一种对类,接口等的很好的组织方式,比如说一个包中的类不想被其他的包中的类进行使用,在一个工程中允许存在相同名称的类,只需要处在不同的包底下即可
import是导入一个具体的类,而不能导入一个具体的包
1)是组织类的一种形式,是为了保证类的唯一性,假设你自己在代码中写了一个Test类,然后你的同事也写了一个Test类,那么就会导致代码无法编译通过
2)package:包,类所在的包,包是一组类的集合,可以防止类名冲突,import static可以导入一些静态方法,import可以导入一个具体的包,这是错的,只可以导入包中的一组类或者多组类;
3)import:引入,指引入了类所需要的类
import是导入包,以区别于同个名称的但是属于不同包的类;
4)在文件上方有一个字段是package,是将当前类导入到包中,等以后要使用的时候,可以使用import将其导入
5)正常情况下,有一个叫做java.util底下的包,他里面有一个package的字段,意思是把当前的类导入包中,以便后续的程序可以使用import来到如使用这个包里面的方法;
6)import java.util.Arrays这个意思就是导入java.util中的Arrays类
7)java.util.*,代表导入包中的所有的类,java在这个地方处理的时候,用谁就自动倒谁;
8)在C语言里面,是全部进行导入,一个类,在不同的包中有不同的内容
9)我们将自定义的类放到自定义的包里面,第一行会有一个package语句
import java.util.Date;//导入包中的一个类,导入util包中的Date类 public class HelloWorld { public static void main(String[] args) { Date date=new Date(); System.out.println(date.getTime());//打印的是一个毫秒级的时间戳 } }
public class HelloWorld { public static void main(String[] args) { java.util.Date date=new java.util.Date(); System.out.println(date.getTime()); } }
我们需要使用java.util的其他类,我们就可以使用import java.util.*,这样我们就可以导入这个包的所有类,但是我们要注意并不是所有类都会被导入进来,而是用到谁我们就会倒入谁
但是我们有时候要显式指定我们要导入的类名,不然还是很容易会出现冲突的情况
一个包底下不能有相同的类,包名不一样,类名不一样,那么即使有相同的类也互不干扰
包名必须是小写字母
import java.util.*; import java.sql.*; public class HelloWorld { public static void main(String[] args) { Date date=new Date(); System.out.println(date.getTime()); } } 上面的代码会编译出错,我们应该这么写:因为是两个包里面都有一个Date类 import java.util.*; import java.sql.*; public class HelloWorld { public static void main(String[] args) { java.util.Date date=new java.util.Date(); System.out.println(date.getTime()); } }
import static java.lang.Math.*;//加上static关键字,以后都不用写Math关键字了 public class HelloWorld { public static void main(String[] args) { double x=30; double y=40; double result=sqrt(pow(x,2)+pow(y,2)); System.out.println(result); } } 下面是另一种写法: import java.lang.Math; public class HelloWorld { public static void main(String[] args) { double x=30; double y=40; double result=Math.sqrt(Math.pow(x,2)+Math.pow(y,2)); System.out.println(result); } }
package Demo; import java.util.Date; import static java.lang.System.*; public class TestDemo{ public static void main(String[] args) { out.println("生命在于运动"); } }
下面是我们经常使用的包:
1.java.lang:系统经常引入的基础类(String,Object),此包在JDK1.1之后进行自动导入
2.java.lang.reflect:java反射编程包
3.java.net:进行网络编程开发包
4.java.sql:进行数据库开发的支持包
5.java.util:是java提供的工具程序包,集合类等等
6.java.io:是IO编程开发包
包的访问权限控制:
当你的成员变量,不加任何的访问修饰限定符的时候,默认是一个包访问权限
1)不加任何的字段作用,相当于是default:默认是包访问权限:只能在同一个包中的相同类或者同一个包中的不同类使用和进行访问
只在包中使用 int a=10,这个变量不可以在包外使用,也就是说,这个变量只能在同一个包中的不同类进行使用和访问,例如如果是一个类,class Test{},他的前面也没有加任何的访问修饰限定符,所以他也只能在一个包中进行访问;只能在包内new,不可以在包外new;
2)加上public之后,就可以在包外进行访问了,同时在包内也可以使用,任何地方都可以进行访问
3)private:只可以在类中进行使用,在同一个包中的同一个类;
4)defalut:默认为在同一个包内可以访问,包外不能访问
只可以在同一个包中进行访问,同一个包中的同一个类,同一个包中的不同类都可以进行访问,别管是子类还是非子类,只要出现了不同的包中,就不可以进行访问;
5)protected:在同一个包中和public没有什么区别,它主要是体现在继承上面的,同一个包中的同一个类,同一个包中的不同类,以及不同包中的子类都可以进行访问;不同包中的非子类是不可以进行访问的(super.属性),不同包必须继承进行访问
上面的这些访问修饰限定符,只是在权限上面进行了限制,并没有说不能用在成员方法,成员变量,构造方法
封装:将数据和操作数据的有机方法进行结合,隐藏对象的属性和实现细节,仅仅提供对外公开的接口来与对象之间实现交互
对于电脑这样的一个硬件系统来说,提供给用户的操作只是:
1)开关机
2)通过键盘输入,显示器,USB插孔等一些对外的接口来实现用户与计算机进行交互,所以说计算机厂商在进行出厂的时候,我们在外部套上壳子,将内部的实现细节进行隐藏起来,仅仅对外面提供一些开关机,鼠标以及一些键盘插孔等操作,让用户和计算机实现交互
3)对类内部的实现细节进行隐藏和封装,对外提供一些公开的接口,供其他的用户来进行访问,所以说要想实现封装,必须修改一些数据的权限,这样的权限是由我们的访问修饰限定符来进行修改的
4)假设有朝一日,如果一个类中的所有属性全部用public字段来进行修饰,比如说下面这个代码:类的创建者把username这个公开的字段名字换成了name,那么外面的代码就会发生报错,所以这个时候无异于增加了用户的使用成本,所以我们提供一个公开的方法来进行让外边的用户访问里面的属性
class Student{ public String username; public String password; } public class Solution{ public static void main(String[] args) { Student student1=new Student(); student1.username="李佳伟"; student1.password="1234567"; } }
同一个包:同一个文件夹
补充和总结:
类和对象:
一:如何定义一个类?如何实例化一个对象?如何访问对象中的成员?
我们如何访问对象中的成员呢?
1)普通的成员变量:通过对象的引用和点号来进行访问,它是属于对象的
2)静态的成员变量:是不依赖于对象的,我们是通过类名和点号来进行访问的,它是属于类的,在方法区,况且只存在一份,因为静态成员变量是类的属性,是JVM加载类的时候开辟空间并进行初始化的
二:代码块:静态代码块,实例代码块
执行顺序是:先是执行静态代码块,在是实例代码块,最后是构造方法
1)实例代码块只有在创建对象的时候才会执行
2)如果说一个类中包含着多个静态代码块,那么在进行编译代码的时候,编译器会按照定义的先后次序依次执行
三:包:
我们如何进行导入JAVA中的包?import
我们如何把自定义的类放到自定义的包里面?是同过package关键字
包是一组类的集合,可以防止类的名字重复
import static可以导入一个静态的方法
import可以导入一个指定的包,说法错误,是导入包中的具体的类
(import java.util这是会发生错误,所以只能这么倒,import java.util.Arrays)
四.封装:
我们对类内部的实现细节进行隐藏,对类提供公开的接口,实现是通过private关键字来进行实现的,我们甚至可以把构造方法,成员方法,成员变量都可以进行修饰
五:对象的初始化:
1)通过构造方法来进行初始化
2)通过直接赋值的方式来进行就地初始化
3)默认初始化,对应的0值,引用类型就是null
六:构造方法:
方法名和类名是一样的,没有返回值,当我们的构造方法执行完成之后,那么对象的实例化就完成了,构造方法是由多个的,所以可以构成重载
注意:
public class Test { public int aMethod(){ static int i = 0;//static修饰类变量,不能定义在方法里面,因为局部变量都是方法的 i++; return i; } public static void main(String args[]){ Test test = new Test(); test.aMethod(); int j = test.aMethod(); System.out.println(j); } }
1)在方法当中定义的变量是局部变量,而静态的变量属于类变量,随着类的加载而被创建,而局部变量是调用该方法的时候,才创建的;
假设你的静态变量如果说是可以定义在方法里面的,但是你的方法肯定是调用的时候才会在栈上面开辟内存空间,那么局部变量肯定是在栈上面的,但是实际上静态变量是在方法区的,这样就会定义冲突
2)所以,此时两种变量的性质是冲突的,Java当中不允许定义局部的静态变量。
class Student{ public String username; public String password; public static void run(){ System.out.println("我是静态的run方法"); } } public class Solution{ public static void main(String[] args) { Student student=null;//虽然是空,但是也是可以调用成功的,因为静态方法不依赖于对象 student.run(); Student.run(); } }
public static void main(String[] args){ String s; System.out.println("s="+s); }
3)上面这个代码会出现编译错误,因为局部变量必须要进行初始化,成员变量可以不初始化,但是可以用默认值
4)下面这个代码的输出结果是:cnt=5,因为先回从上到下执行静态代码块
public class Test{ static int cnt = 6; static{ cnt += 9; } public static void main(String[] args){ System.out.println("cnt = " + cnt); } static{ cnt /=3; }; }
5)这段代码的执行结果是:aaabbb
class Test{ public String toString() { System.out.print("aaa"); return "bbb"; } } public static void main(String[] args) { Test test = new Test(); System.out.println(test); }
6)此时打印的结果是false,因为Pabby是定义在方法里面的,况且Pabby是静态成员变量,是可以在静态成员方法里面访问的
public class Pvf{ static boolean Paddy; public static void main(String args[]){ System.out.println(Paddy); } }
7)下列使用正确的是:下面都可以进行访问虽然要被private修饰,但是因为在类内,所以是直接可以访问的
public class Test{ private float f=1.0f; int m=12; static int n=1; public static void main(String args[]){ Test t=new Test(); } }
A.t.f = 3.0 B.this.n C.Test.m D.Test.n
A选项应该改成3.0f,浮点数应该加上一个.f,因为在JAVA中默认是的小数都是double类型的
B选项应该改成Test.n,因为静态成员变量应该用类名.变量名来进行访问
C选项是普通成员变量,应该通过Test t=new Test();通过引用来访问
8)在一个构造方法里面是不可以直接通过下面的方式来进行调用的直接使用
A()来进行调用构造方法(类名()来进行调用构造方法)
class A{ public String username; public String password; A(){ this("李佳伟","12503487"); // A("李佳伟","12503487");这样调用是错误的 System.out.println("今天心情不好"); } A(String username,String password){ this.username=username; this.password=password; } }
9)下面代码:下面代码会出现报错,因为子类构建的时候必须先帮助父类进行构造,所以在public Dervied()里面应该先帮助父类来进行构造:调用super(字符串)
class Base{ public Base(String s){ System.out.print("B"); } } public class Derived extends Base{ public Derived (String s) { System.out.print("D"); } public static void main(String[] args){ new Derived("C"); } }
对象的打印:println方法源码分析,当我们想要打印一个对象的时候,会默认调用这个Object.toString方法,我们可以在这个对象中重写toString方法,这是就发生了向上转型
public void println(Object x) { String s = String.valueOf(x);//在上面那个题,s最后就变成了bbb synchronized (this) { print(s); newLine(); } }
public static String valueOf(Object obj) { return (obj == null) ? "null" : obj.toString(); //最终会返回子类调用toString()方法的结果 }
public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
public void print(String s) { if (s == null) { s = "null"; } write(s);//将s显示在控制台上面 }