文章目录
javaSE笔记
1、static关键字
//当方法用static关键字声明时,这个方法在他所在的类创建时,就创建了(方法被创建的早)
//所以被static声明的方法不能调用没有声明static的方法
public static void a(){
b(); //此处会报错
}
//而未用static声明的方法是在类被实例化的时候创建的
public void b(){
a(); //这个可以有
public class Student {
{
//匿名代码块,在创建对象的时候执行一次
System.out.println("匿名代码块");
}
static {
//静态代码块,在类加载的时候就创建了,且永久的只执行一次
System.out.println("静态代码块");
}
public Student(){
System.out.println("构造方法");
}
}
public class Test {
public static void main(String[] args) {
new Student();
System.out.println("====");
new Student();
}
}
//结果(有序):静态代码块
// 匿名代码块
// 构造方法
// ====
// 匿名代码块
// 构造方法
//所以static代码块在类创建的时候就存在了,只在第一次new对象的时候执行一次;
静态导入包
import static java.lang.Math.*;
//可不写类名直接用方法
System.out.println(random());
//0.1242972520655512 随机数
被final修饰的类不能被继承
用static声明的属性是所有对象共享的,懂通过一个对象改变这个属性时,其他对象调用这个属性也会发生改变
2、java的值传递
public class demo02 {
public static void main(String[] args) {
int a=1;
System.out.println(a);
demo02.change(a);
System.out.println(a);
}
public static void change(int b){
b=10;
}
}
//定义一个int类型的变量,当调用方法时,会把实参a的值传递形参b,在方法中改变了b的值,但是并没有改变a的值
3、引用传递
引用传递是传递了一个对象,但是他的本质还是值传递
//值传递不会改变值,而引用传递会改变值
public class demo03 {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.name);//null
demo03.change(person);
System.out.println(person.name);//大傻子
}
public static void change(Person person){
person.name = "大傻子";
}
}
class Person{
String name;
}
4、对象与类、栈和堆
public class Pet {
public String name;
public int age;
public Pet(){
}
public Pet(String name, int age) {
this.name = name;
this.age = age;
}
public static void shout(){
System.out.println(this.name+"叫了一下");
}
}
//创建一个类,有name和age两个属性,一个shout方法
给这个类new两个对象,cat和dog
public class demo04 {
public static void main(String[] args) {
Pet cat = new Pet();
cat.name = "菠菜";
cat.age = 3;
cat.shout();
Pet dog = new Pet();
dog.name = "波太郎";
dog.age = 3;
dog.shout();
}
}
在对象创建之前(new之前),先在类中的方法区加载类和类中的静态方法,当实例化一个对象时,在栈中生成一个引用变量名(所以对象属于引用数据类型),栈—>堆,指向堆中非方法区中的某一模块!!!main方法在栈的最下面
5、继承
extends(扩展);子类继承父类,那么子类可以调用父类的方法和属性,但是private声明的不能被继承,当子类和父类具有相同的方法名或属性名时,使用子类的对象调用方法或属性时,优先使用子类的,可用this和super来区分;
且当实例化子类时,会首先检测他的父类有没有被实例化,如果父类没有被实例化,则先实例化父类(调用父类的构造器super() )
super注意点:
-
调用父类的构造方法,必须在构造方法的第一个
-
只能出现在子类中
-
super和this不能同时调用构造方法
6、重写
需要有继承关系,则子类重写父类的方法
- 方法名必须相同
- 参数列表必须相同
- 修饰符:范围可以扩大单不能缩小,public>protected>default>private
- 抛出的异常:范围可以被缩小,但不能扩大
7、多态
public class Person { //父类
public void run(){
System.out.println("Person-->run");
}
public void read(){
System.out.println("Person-->read");
}
}
public class Student extends Person { //子类
@Override
public void run() { //重写父类的方法
System.out.println("Student-->run");
}
public void write(){ //子类独有的方法
System.out.println("Student-->write");
}
}
public class test { //测试
public static void main(String[] args) {
//一个对象的实际类型是确定的
//new Person();
//可以指向的引用类型就不确定了:父类的引用指向子类
//子类(Student) 能调用的方法都是自己或者父类的
Student s1 = new Student(); //子类的对象new子类
//父类型(Person)能指向子类,但不能调用子类独有的方法
Person s2 = new Student(); //父类的对象new子类
//对象能执行哪些方法,主要看左边,和右边关系不大,用时执行哪个方法看右边
s1.run(); //Student-->run
s2.run(); //Student-->run
s1.read(); //Person-->read
}
}
多态注意事项
- 多态是方法的多态,属性没有多态
- 父类和子类,有联系 类型转换异常
- 存在关系:继承关系,方法需要重写,父类引用指向子类Father f1 = new Son();
- 不能被重写的方法:
- static 方法,属于类,不属于实例
- final 修饰的方法
- private 方法:不能被继承
8、abstract–>抽象类
继承抽象类的所有类都必须要实现它的方法(子类时普通类)
接口可以多继承
- 抽象类不能new,只能靠子类去实现:约束
- 抽象方法必须在抽象类中,抽象类中可以有普通方法
9、内部类
9.1、普通内部类和静态内部类
一个类可以定义在另一个类的内部,叫做内部类
public class Outer { //外部类
private int id = 10;
private void out(){
System.out.println("这个方法在外部类里面");
}
public class Inner{ //内部类
public void in(){
out();
System.out.println("这个方法在内部类里面");
}
public void getId(){
System.out.println(id);
}
}
}
public class Tset {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
//要活得内部类的实例,就要先用外部类的对象去new内部类,得到的是一个Outer.Inner类型的对象
inner.in();
}
}
- 内部类的对象可以调用外部类的私有属性和方法
- 静态内部类,用static关键字修饰,这时就不能调用非静态的属性了
9.2、局部内部类和匿名内部类
**局部内部类:**写在方法里面的类
class demo {
public void method(){
class A{
//暂时没有什么意义,就是花里胡哨
}
}
}
匿名内部类(略)
10、异常(Exception)
五个关键字:try、catch、finally、throw、throws
int a=0;
int b =1;
System.out.println(b/a);
//会抛出异常:Exception in thread "main" java.lang.ArithmeticException: / by zero
//被除数不能为0
上述代码会造成异常,此时程序会报错停止,但是我们有的时候并不想让异常报错使程序停止,那么我们可以对有可能出异常的区域进行检测,如果发生异常,就抛出异常,此时程序依然可以向下执行;而finally则是无论程序出不出异常,finally里面的代码都会被执行,finally可以不要。
public class Test {
public static void main(String[] args) {
int a=0;
int b =1;
try{ //Ctrl Alt + t
System.out.println(b/a);
}catch (ArithmeticException e){
//ArithmeticException是想要获得异常类型;最大是Throwable
System.out.println("以上程序出现异常");
}catch (Throwable e){ //catch可以有多个,但是大的必须在后面
e.printStackTrace();
}finally {
System.out.println("finally");
}
System.out.println("结束");
}
}
//结果(有序):
// 以上程序出现异常
// finally
// 结束
主动抛出异常–throw、throws
public class Test01 {
public static void main(String[] args) throws Exception{ //当在方法中处理不了一个异常,这时就要在方法上跑处置异常了
int a = 0;
int b = 6;
if (a==0){
throw new ArithmeticException();//主动抛出异常,在方法中
}
}
}
//结果:Exception in thread "main" java.lang.ArithmeticException(算数异常)
自定义异常:
//自定义的异常类
public class MyException extends Exception {
private int detail ; //一个int类型的属性
public MyException(int detail) {
this.detail = detail;
}
@Override
public String toString() { //打印异常信息
return "MyException"+detail;
}
}
public class ExceptionTest {
//一个可能会出现异常的方法
static void test(int a) throws MyException {
System.out.println(a);
if (a>10){
throw new MyException(a); //满足情况抛出异常
}
System.out.println("OK");
}
public static void main(String[] args) {
try {
test(11);
} catch (MyException e) {
System.out.println(e);
}
}
}//结果:
//11
//MyException11
11、补充:String
11.1、关于String类型和ASCII码及类型转换
众所周知当int型和字符串类型相加时,int类型可以自动转换为字符串类型,但是转化时是有顺序的
public class Test01 {
public static void main(String[] args) {
String str01 = "a"+ 1 + 2;
int str02 = 'a' + 1 + 2;
String str03 = 1 +2 + "a";
System.out.println(str01); //a12
System.out.println(str02); //100
System.out.println(str03); //3a
}
}
11.2、关于String
-
一个字符串就是String类的匿名对象,匿名对象就是已经开辟了堆内存空间的并可以直接使用的对象
public class Test { public static void main(String[] args) { System.out.println("hello".equals("helo")); } } //false
输出结构为false,说明一个字符串确实可以调用String类中的方法,证明了一个字符串就是String类的匿名对象。
-
关于内存
String str1 = "hello";
此种形式声明了一个变量,实际上就是在堆中开辟好的堆内存空间的使用权给了str1这个对象;
这种方法还有一个好处就是,如果一个字符串已经被一个名称所引用,则以后再有相同的字符串声明时,不会再开辟新的空间,即:
public class Test {
public static void main(String[] args) {
String str1 = "hello";
String str2 = "hello";
String str3 = "hello";
System.out.println(str1==str2); //ture
}
}
-
关于声明问题
String str = new String("hello");
此方法声明会开辟两块堆内存空间,其中有一块将会成为垃圾。
-
字符串的内容不可改变
当改变一个字符串的内容时,其实并没有改变这个字符串在堆内存的内容,而是重新开辟一个空间,存入新的内容,在把栈中变量的引用指向新的内存空间。
public class Test { public static void main(String[] args) { String str1 = "hello"; System.out.println(str1.hashCode()); //99162322 str1 = "fds"; System.out.println(str1.hashCode()); //101237 } }