java----语言基础


 重载:

//同一个类中,方法名相同,参数列表不同[java就是靠不同的参数列表来寻找方法的],返回值可以任意
public class Demo {
	public static void main(String[] args) {
		float num1 = 3;
		float num2 = 4;
		float x = add(num1,num2);
		System.out.println(x);
	}
	public static int add(int a,int b){
		return a+b;
	}
	public static float add(float a,float b){
		return a*b;
	}
}

 

 可变参数:

sayhi(String... str){
    
}    
此时的str可以传递,也可以不传递。但是可变参数必须放在最后面。它本身是一个数组

  

 static:

static修饰字段

使用static关键字修饰一个字段:声明的static变量实际上就是一个全局变量

static修饰的方法不可以重写,所以接口和抽象方法中定义的static方法必须是需要方法体的。另外接口中定义的变量必须附初始值,抽象类定义的变量可以不需要附初始值。

使用static关键字修饰一个方法:可以直接使用类调用方法,和对象没有关系了

使用static关键字修饰一个类:内部类

如果需要了解跟多static关键字修饰字段,参考我的另一篇博客:https://www.cnblogs.com/yanxiaoge/p/10658660.html

public class Demo {
    public static void main(String[] args){
    System.out.print(Test.name);//一般定义静态字段,最好又类来调用;
  //System.out.print(Test.name1);   //只有定义了静态字段,类才可以直接调用
}
}
 
class Test{
   String name1 = "dddsdfsd";
       static String name = "dd";
    
}

static修饰方法

public class Demo {
    public static void main(String[] args){
    Test.setCountry("中国");
    
    Test h = new Test();
    System.out.print(h.country);
    }
}
class Test{
	static String country;
	public static void setCountry(String country){ //静态方法只能访问静态字段;不能访问非静态字段
		Test.country = country;
	} 
}

static代码块和构造代码块:

如果Test类继承了父类,会先执行父类的静态代码块和构造代码块(如果是创建对象的情况下)

static{}:代码块是类的加载过程中初始化阶段执行的。和new对象没有任何关系,比如Test.静态属性,也同样会触发static{},只是在new 对象过程中,如果发现当前类还没有被加载到内存,就会将类加载到内存,在初始化过程中执行了<clinit>() 方法,如果static{}中有打印信息,就会被打印出来,如果第二期new 对象的时候,发现类已经加载内存了,就不会再进行初始化了.也就是为什么多次new 对象,static 变量只有一个的原因了(全局共享),而且这个变量就和对象没有任何关系了(但是还是可以通过对象访问静态变量和静态方法的,一个对象对静态变量的修改会影响到另一个对象)

public class Demo {
    public static void main(String[] args){
    	Test t = new Test();
    	Test t1 = new Test();
    }
}
class Test{
	static{
		System.out.println("静态代码块");//在类中使用static定义,最先执行,只会创建一次(当创建第二个对象是,不会再执行该代码,static只存储一次)
	}
	{
		System.out.println("构造代码块");//在类中定义,优先构造方法执行,每次创建对象都会执行
	}
	public Test(){
		
		{
			System.out.println("普通代码块"); //在方法中定义,方法被调用执行
		}
		System.out.println("我是构造方法");
	}
}

通过类调用静态方法只会调用静态代码块,多次调用也会执行一次静态代码块。(如果继承父类,同样会先执行父类的)

public class Demo {
    public static void main(String[] args){
        Test.t();
        Test.t();
    }
}
class Test{
    static{
        System.out.println("静态代码块");//在类中使用static定义,最先执行,只会创建一次(当创建第二个对象是,不会再执行该代码,static只存储一次)
    }
    {
        System.out.println("构造代码块");//在类中定义,优先构造方法执行,每次创建对象都会执行
    }
    public Test(){
        {
            System.out.println("普通代码块"); //在方法中定义,方法被调用执行
        }
        System.out.println("我是构造方法");
    }
    public static void t(){

    }
}

Test t = null;不会有任何操作

调用通过类调用final修饰的字段(同时被static修饰,不然不能被类直接调用)不会初始化。

public class Demo {
    //main方法会被调用,所有static会被执行
    static {
        System.out.println("x");
    }
    public static void main(String[] args){
        //这样不会执行Test中的任意代码块
        Test t = null;
    }
}
class Test{
    static{
        System.out.println("静态代码块");//在类中使用static定义,最先执行,只会创建一次(当创建第二个对象是,不会再执行该代码,static只存储一次)
    }
    {
        System.out.println("构造代码块");//在类中定义,优先构造方法执行,每次创建对象都会执行
    }
    public Test(){
        {
            System.out.println("普通代码块"); //在方法中定义,方法被调用执行
        }
        System.out.println("我是构造方法");
    }
}

下面输出结果:构造。构造。静态。构造

public class B
{
    public static B t1 = new B();
    public static B t2 = new B();
    {
        System.out.println("构造块");
    }
    static
    {
        System.out.println("静态块");
    }
    public static void main(String[] args)
    {
        B t = new B();
    }
}

 

 final:

private static final int NUM = 10;  //final表示该字段为常量,通常全部大写

final 修饰一个类,则该类不能被继承;final不可以修饰抽象类和接口

final 修饰一个方法不能重写,和static一样。

将类、方法、变量声明为final能够提高性能,这样JVM就有机会进行估计,然后优化。

接口中的变量都是final

常量类

public class Demo {
    public static void main(String[] args){
        Person person = new Person(11);

    }
}

class Constant{  //将常量专门放在一个类中,让其他的类继承他[常量不一定必须初始化,可以在构造器中默认赋值(如果采用这种方法给常量赋值,常量不能用static修饰)]
    public static final int NUM = 10;  //加上static,目的不用创建了对象,就可以直接调用常量;

}

class Person extends Constant{
    private final int NUM;
    public Person(int id){
    NUM = id;          //在构造器中的初始化
    }

    {
        System.out.println(Constant.NUM);
    }
}

  

 volatile:

背景

  数据的计算(1+1),首先是从内存中加载代cpu缓存中,在加载到cpy计算。cpu计算完成返回的结果放到cpy缓存区,至于什么时候在返回到内存,是不确定的,看cpu空闲时间。有没有方法能让计算结果立刻返回到内存中。

  

 

  volatile是Java提供的一种轻量级的同步机制,在并发编程中,它也扮演着比较重要的角色。同synchronized相比(synchronized通常称为重量级锁),volatile更轻量级,相比使用synchronized所带来的庞大开销,但是注意 volatile不能确保原子性,在访问volatile变量时,不会执行加锁操作,因此也就不会执行线程阻塞。所以volatile变量是一种比sychhronized关键字更轻量级的同步机制。

原子性:原子性就是指该操作是不可再分的。不论是多核还是单核,具有原子性的量,同一时刻只能有一个线程来对它进行操作。简而言之,在整个操作过程中不会被线程调度器中断的操作,都可认为是原子性。比如 a = 1;

volatile的适用场景:

  1、对变量的写入操作不依赖其当前值(如 number++ 、count = count * 5等)

  2、该变量没有包含在具有其它变量的不变式中

  3、volatile关键字另一个作用就是禁止指令重排优化

参考:https://www.cnblogs.com/xuwenjin/p/9051179.html

https://www.cnblogs.com/chengxiao/p/6528109.html

 

补充可以看看CAS:https://blog.csdn.net/v123411739/article/details/79561458

 面对对象:

对象被创建的步骤

1.分配对象空间,并将对象成员变量初始化为0或空

2.执行属性值的显式初始化

3.执行构造方法(此时的对象已经被创建,我们可以在这一步对对象进行进一步的初始化工作)

4.返回对象的地址给相关的变量

public class Demo {
	public static void main(String[] args){
		Horse h = null;
		h = new Horse();
//		h.name = "dd";
		h.eat();
		h = null; //释放对象
	}
}

class Horse{
	String name;
	public void eat(){
		System.out.println(name);
	}
	
}

封装性:

public class Demo {
	public static void main(String[] args){
		Horse h1 = new Horse();
//		h1.name = "小明";//由于 name设置了私有字段,此时在给对象赋值,会报错;
		h1.setName("小明");
		System.out.println(h1.getName());
}
}
class Horse{
	//属性的封装
	private String name;
	private int age;     //成员变量,在类中定义,在堆内存,对象清空,则成员变量清空,有默认初始值,像String引用变量初始值为null,int的初始值为0;
	public void setName(String name){ //参数也是局部变量
		int a = 111; //局部变量;在方法中定义,在栈内存,方法调用完毕,就清空,没有初始值,必须定义,赋值后,才能调用。
		this.name = name;
	}
	public String getName(){
//		return name;
		return this.name;  // 可以使用this调用其他方法和属性,this可以省略,this前面可以加上类名  Horse.this.name();
	}
}

构造方法和构造方法的重载:

类似python中的__init__(self){}

public class Demo {
	public static void main(String[] args){
		Horse h = new Horse();
		Horse h2 = new Horse(1);
	}
}
class Horse{
	public Horse(){ //方法名称和类名相同,没有返回值
		System.out.println("我是构造方法");
	}
	public Horse(int a){
		System.out.println("a="+a);
	}
}

构造方法之间的调用,用this()

public class Demo {
	public static void main(String[] args){
		Horse h2 = new Horse(1);
	}
}
class Horse{
     public Horse(){  //默认构造方法,可以保留
      
    }
	public Horse(String b){ //方法名称和类名相同,没有返回值
		System.out.println(b);
	}
	public Horse(int a){
		this("11");  //调用另一个构造方法,注意,这条语句,只能放在最前面,否则报错;,限制了,不能调用多个;
          this("22");  //报错,只能调用一个
		System.out.println("a="+a);
	}
}

 对象之间的关联:

public class Demo {
    public static void main(String[] args){
    	Hero hero1 = new Hero("刘备");
    	Weapon weapon1 = new Weapon("双股剑");
    	
    	hero1.setWeapon(weapon1);//将对象传递给一个对象,实现对象之间的关联
    	
    	System.out.println(hero1.getWeapon().getName());
    	
} 
}
class Hero{
    //属性的封装
	private String name;
	private Weapon weapon;
	
	public Hero(String name){
		this.name = name;
	}
    
    public void setWeapon(Weapon weapon){
    	this.weapon = weapon;
    }
    public Weapon getWeapon(){
    	return this.weapon;
    }
}
class Weapon{
	private Hero hero;
	private String name;
	public Weapon(String name){
		this.name = name;
	}
	public void setHero(Hero hero){
		this.hero = hero;
	}
	public String getName(){
		return this.name;
	}
}

继承:

方法的重载:发生在同一个类中,函数名相同,参数列表不相同,与返回值返回值(类型)无关;

方法的重写:发生在继承的关系中,函数名相同,参数列表相同,返回值(类型)需要相同。子类的访问修饰符需要大于或者等于父类的访问修饰符,子类的异常声明要小于或等于父类的异常声明,如果方法被private 、static修饰,那么方法不能被继承/重写。 final修饰,只能继承,不能重写

public class Demo {
    public static void main(String[] args){
    	Dog dog = new Dog();    //子类创建对象时 ,也会 自动 调用父类的默认的构造方法
    	System.out.println(dog.name);
    	dog.print();
    }
}

class Animal{
	protected String name = "动物";
	public Animal(){
		System.out.println("我是Animil 默认构造方法");
	}
	public Animal(String name){
		System.out.print("我是Animial  传参构造方法");
	}
	public void print(){
		System.out.println("Animal");
	}
}
class Dog extends Animal{   //继承的写法
	public Dog(){
		super("传值");       //如果有super,就会继承super所指的构造方法,具体执行那一个,看传参的列表
//		super();            //如果没有传值,就会执行父类的默认的构造方法,前提父类必须保留默认的构造方法;
							//注意1:默认情况下,会自动添加super(),如果自己写了super,就会覆盖默认的
							//注意2:super(),只能方法最开始的位置
	}
	public void print(){
		super.print();     //继承父类的方法;
		System.out.println("Dog");
	}
}

 

 抽象类:

1、抽象类可以没有抽象方法,有抽象方法的一定是抽象类

2、非抽象类继承抽象类必须实现所有的抽象方法

3、抽象类可以继承抽象类,可以不实现父类的抽象方法

4、抽象类可以有方法实现和属性

5、抽象类不能被实例化

6、抽象类不能声明final

7、抽象类可以有构造方法

public class Demo {
    public static void main(String[] args){
    	Dog dog = new Dog();
    }
}

abstract class Animal{    //声明该类是一个抽象类,只能继承,不能实例化
	{
		System.out.println("可以有构造方法");
	}
	public abstract void eat();  //可以没有抽象方法  ,如果有了抽象方法,该类必须是抽象类,并且该抽象方法必须子类实现;
	public void run(){           //普通的方法可以不用被实现
		System.out.print("我可以跑");
	}
}

class Dog extends Animal{
	public void eat(){
		
	}
}

 

抽象类设置了很多属性,这些属性有什么意义?

  当我们子类继承父类,子类实例化的时候就可以使用super(),像父类传值。父类就可以在特定的场景使用这些属性。

  当然,有些属性是由父类自己设置的。

 接口:

1、抽象类实现接口,可以不实现接口的方法,非抽象类,必须实现接口的所有的方法;

2、接口的方法没有声明访问修饰符,默认为public

3、接口不能有构造方法,接口不能被实例化

4、接口之间的继承用extends ,定义接口用interface ,类实现接口用implements

5、接口只能定义常量,抽象方法,(jdk1.8之后有默认的实现方法,和静态方法)

6、final不可以修饰接口

public class Demo {
    public static void main(String[] args){
    	Person person = new Person();
    	person.print();  //默认的方法实现;
    }
}

interface IEat{
//	public abstract void eat();
	void eat();  //简写,定义抽象方法
	
//	public final static int NUM = 10;
	int NUM = 10; //简写,定义常量
	
	public default void print(){
		System.out.println("默认方法实现");  //jdk1.8之后有 默认方法实现(加上default),不能有其他的方法实现
	}	
}
interface ISleep{
	void sleep();
}
interface IRun extends IEat,ISleep{   //接口可以有多继承
	void run();
}

class Person implements IRun,ISleep{  //接口的实现,类可以继承多个接口(不是接口的继承)
	public void sleep(){}             //必须实现接口的所有的方法
	public void run(){}
	public void eat(){}
	
}

  

 多态:  

 

public class Demo {
    public static void main(String[] args){    	
    	Chick smailchick = new SmailChick();  //用父类的引用指向子类对象,(用大的类型接受小的类型,向上转型,自动转换)
    	eat(smailchick);
    	
    	SmailChick smailchick2 = new SmailChick();
    	eat(smailchick2);
    	
    	Chick bigchick = new BigChick();
    	eat(bigchick);
    }
    public static void eat(Chick c){  //多态性,Chick可以接受比他小的或者等于他的类型,(例如int可以接受short类型)
    	c.eat();
//    	c.song();  //直接写会报错,原因Chick中没有song方法,在运行的时候,c才是所new的对象,在编译的时候c还是chick
    	
    	if(c instanceof BigChick){              //在转换之前做类型的判断
//    		BigChick bigchick = (BigChick)(c);  //若果父类中没有定义song()方法,就需要   强制转换  将Chick转变成BigChick
//    		bigchick.song();
    		((BigChick)c).song();               //简写
    	}
    }
}

abstract class Chick{
	public abstract void eat();
}
class SmailChick extends Chick{
	public SmailChick(){
		super();
	}//默认自动添加
	public void eat(){
		System.out.println("我是小鸡,我爱吃米");
	}
}

class BigChick extends Chick{
	public void eat(){
		System.out.println("我是大鸡,我爱吃虫");
	}
	public void song(){
		System.out.println("我是大鸡,我会唱歌");
	}
}

this的本质 

指明当前的对象,不能放到static静态方法中

class Test{
    int a;
    public Test(int a){
        //给成员变量进行赋值
        this.a = a;
    }
    public Test(){
        //调用另一个构造方法,只能放在代码的第一行(所以只能有一个)
        this(1);
    }
}

java中的new到底为我们做了什么?

    参考https://www.cnblogs.com/KingIceMou/p/7245446.html

补充

访问修饰符

 

 

 内部类:

内部类的好处

  可以使用外部类的元素

class Demo extends B{
    private String a;
    class Test{
        public void test() {
            System.out.println(a);        
        }
    }
}

  匿名内部类可以加private protected修饰,隐藏对象

public class Demo {
    public static void main(String[] args){
        A a = new A();
        //实现隐藏
        Instance in = a.getIn();
    }
}
interface Instance{}
class A{
    public B getIn(){
        return new B();
    }
    private class B implements Instance{
    }
}

  可以实现多重继承

class A {
    public String name() {
        return "小明";
    }
}
class B {
    public int age() {
        return 18;
    }
}
class Test {
    private class test1 extends A {
    }
    private class test2 extends B {
    }
    public String name() {
        return new test1().name();
    }
    public int age() {
        return new test2().age();
    }
    public static void main(String args[]) {
        Test mi = new Test();
        System.out.println("姓名:" + mi.name());
        System.out.println("年龄:" + mi.age());
    }
}

  避免修改接口而实现同一个类中两种同名方法的调用

    你的类要继承一个类,还要实现一个接口,可是你发觉你继承的类和接口里面有两个同名的方法怎么办?

    未使用内部类的情况

interface A{
    void test();
}
class B{
    void test(){
        System.out.println("B");
    }
}
class Demo extends B implements A{
    @Override
    public void test() {
        //这种方法就调用不到B类的方法了
    }
}

    使用内部类的情况

interface A{
    void test();
}
class B{
    void test(){
        System.out.println("B");
    }
}
class Demo extends B{
    //使用内部类来实现接口
    class Test implements A{
        @Override
        public void test() {

        }
    }
}

成员内部类:

public class Demo {
    public static void main(String[] args){
    	A a = new A();
    	
//    	A.B b = a.new B(); //创建内部类,通常不建议这样调用
//    	b.print();
    	
    	a.Bprint();        //通过接口来创建内部类,并调用类的方法
    }
}

class A{
	//成员内部类
	public void Bprint(){
		B b = new B();
		b.print();
	} 
	//成员内部类,建议设置私有.内部调用
	private class B{
		public void print(){
			System.out.println("测试");
		}
	}
}

方法内部类:

public class Demo {
    public static void main(String[] args){
    	A a = new A();
    	a.Aprint();       
    }
}

class A{
	//方法内部类
	public void Aprint(){
		int x = 1;
//		x++;  //由于内部类调用了局部变量x,所以x不能修改;
		System.out.println(x);
		class B{
			public void print(){
				System.out.println("测试"+x); //一旦方法内部类中调用了局部变量,该变量默认是final,不可以被修改;
			}
		}
		B b = new B();  //方法内部类只能在该方法内实例化
		b.print();
	} 
	
}

解释:为什么方法内部类中类调用局部变量,该变量必须修饰为final(在jdk1.8之后,可以不用加,解释器会默认加上)?

当上面的Aprint方法结束了。方法直接出栈,栈中里面的局部变量清空,但是对象(内部类),可能GC垃圾回收机制,还没有将对象回收掉。而对象有调用着局部变量,此时就会报错,所以必须将该局部变量修饰为final,放在堆的常量区,这个即使方法出栈了,局部变量也不会被清空,而修饰了finnal的局部变量,则不能在进行修改操作了。

注意:没有被类调用的变量不会默认为final,可以进行修改操作;

内部类中可以使用不加final的静态变量

静态内部类:

静态内部类不依赖对象,所以开发项目的时候优先考虑

使用静态内部类不用担心内存泄漏的问题;

public class Demo {
    public static void main(String[] args){
    	A.B b = new A.B();
    	b.print();
    }
}

class A{
	//静态内部类 ,不能调用非静态的方法和属性;
	static class B{  
		public void print(){
			System.out.println("静态内部类");
		}
	}
}

匿名内部类:

继承式匿名内部类

接口式匿名内部类

参数式匿名内部类

注意事项:

  1、不能有构造方法(没有名字),只能有一个实例

  2、不能定义任何静态成员,静态方法(内部类依赖对象,对象和静态是没有关系的)

  3、不能是private   static  protected  public (没有类,没办法加修饰符) 

  4、一定是是在new后面,用其隐含实现一个接口或者继承一个类

  5、匿名内部类是局部的,所以局部内部类的所有的限制都对其生效

public class Demo {
    public static void main(String[] args){
    	print1();
    	print2();
    	
    	print3(new C(){
    		public void print(){
    			System.out.println("参数式内部类");
    		}
    	});
    }
    public static void print1(){
    	A a = new A(){
    		public void print(){
    			System.out.println("继承式内部类");
    		}
    	};//注意一定要有分号;
    	a.print();
    }
    public static void print2(){
    	B b = new B(){
    		public void print(){
    			System.out.println("接口式内部类");
    		};
    	};
    	b.print();
    }
    public static void print3(C c){
    	c.print();
    }
}

abstract class A{
	public abstract void print();
}

interface B{
	void print();
}

abstract class C{  //interface class C{} 一样
	public abstract void print();
}

总结:

每个内部类能独立的继承或一个(接口)的实现,所以无论外部类是否是否已经继承了某个(接口的)实现,对于内部类没有影响。

并且内部类为多继承的实现,提供了解决方案;

public class Demo {
    public static void main(String[] args){
    	C c = new C();
    	c.print();
    }
}

abstract class A{
	
}
abstract class B{
	public abstract void print();
}

class C extends A{
	class D extends B{
		public void print(){
			System.out.print("测试");
		}
	}
	public void print(){
		D d = new D();
		d.print();
	}
}

内部类访问外部内对象属性

class A{
    private User user;
    class B{
        //如果需要访问user
        User u = A.this.user;
    }
}

 

 父子类之间转换:

 

Father f1 = new Father();
Father f2 = new Son();
Son s1 = new Son();

//子类强转父类,不会有任何问题,只是不能在调用子类的方法,如果想调用子类的方法,之间在转换成子类就行,因为这个对象本身就是子类,本质没有改变,所以我们看方法都是用父类接受对象,在方法中在对对象进行转换成子类(判断是不是属于子类)
(Father)s1
(Son)(Father)s1


//f2本身就是子类,f1本身就是父类
(Son)f1 报错
(Son)f2 不报错

  

 

posted @ 2019-04-03 17:21  小名的同学  阅读(199)  评论(0编辑  收藏  举报