Categorías
Classes & Interfaces

Ruta de paquete y clase

Esta pregunta trata sobre cómo usar correctamente la variable estática de una clase en otro paquete.

1. Dados los dos archivos fuente:

1.  package com.sun;
2.  public class PkgAccess {
3.    public static int tiger = 1414;
4.  }

Y:

1.  import static com.sun.PkgAccess.*;
2.
3.  public class PkgAccess2 {
4.
5.    int x1 = PkgAccess.tiger;
6.    int x2 = tiger;
7.    int x3 = com.sun.PkgAccess.tiger;
8.    int x4 = sun.PkgAccess.tiger;
9.  }

¿Cuáles dos son verdaderas? (Escoge dos.)

  • 1 – La clase PkgAccess2 se compila.
  • 2 – La compilación falla debido a un error en la línea 5.
  • 3 – La compilación falla debido a un error en la línea 6.
  • 4 – La compilación falla debido a un error en la línea 7.
  • 5 – La compilación falla debido a un error en la línea 8.
  • 6 – Las clases PkgAccess y PkgAccess2 se compilan.

Respuesta: 2 y 5 son verdaderas.

Explicación: Cuando dice «import static com.sun.PkgAccess. *;» está importando cada valor estático de la clase PkgAccess, por lo que puede llamar a ese valor usando

com.sun.PkgAccess.tiger  // full path to access static "tiger" variable
tiger // use directly the static variable (because we import it !)

no puedes decir

sun.PkgAccess.tiger // because the path is incorrect
PkgAccess.tiger // same as above

Cuando ingrese ese código en IDE como Netbeans, le permitirá cambiarlo.

Categorías
Classes & Interfaces

Notas de la “Guía de estudio del programador certificado por Sun para Java 6”

1. El estático El modificador se usa para crear variables y métodos que existirán independientemente de las instancias creadas para la clase. Todos los miembros estáticos existen antes de que usted cree una nueva instancia de una clase, y solo habrá una copia de un miembro estático independientemente del número de instancias de esa clase. En otras palabras, todas las instancias de una clase dada comparten el mismo valor para cualquier variable estática dada.

2. Las invocaciones de métodos polimórficos se aplican solo a métodos de instancia. Siempre puede hacer referencia a un objeto con un mas general tipo de variable de referencia (una superclase o interfaz), pero en tiempo de ejecución, lo ÚNICO que se selecciona dinámicamente en función de la objeto real(en lugar del tipo de referencia) son métodos de instancia. No métodos estáticos. No variables. Solo los métodos de instancia anulados se invocan dinámicamente según el tipo del objeto real.
Ejemplo:

class Mammal{
    String name = "furry ";
    String makeNoise(){
        return "generic noise";
    }
}
class Zebra extends Mammal{
    String name = "stripes ";
    String makeNoise(){
        return "bray";
    }
}
public class ZooKeeper {
    public static void main(String[] args){
        new ZooKeeper().go();
    }
    void go(){
        Mammal m = new Zebra();
        System.out.println(m.name + m.makeNoise());
    }
}
Result: furry bray

3. El tipo de una variable de referencia determina los métodos que se pueden invocar en el objeto al que hace referencia la variable.

4. Una variable de referencia puede declararse como un tipo de clase o un tipo de interfaz. Si la variable se declara como un tipo de interfaz, puede hacer referencia a cualquier objeto de cualquier clase que implemente la interfaz.

5. Para resumir, qué versión anulada del método a llamar se decide en tiempo de ejecución según el tipo de objeto, pero qué versión sobrecargada del método a llamar se basa en el tipo de referencia del argumento pasado en compilar hora.

6. La cohesión es el principio OO más estrechamente asociado con asegurarse de que una clase esté diseñada con un propósito único y bien enfocado.

La encapsulación es el principio OO más estrechamente asociado con la ocultación de detalles de implementación.

El acoplamiento es el principio OO más estrechamente asociado con asegurarse de que las clases conozcan otras clases solo a través de sus API.

Polimorfismo: el principio OO más estrechamente asociado con permitir que un solo objeto se considere que tiene muchos tipos.

Categorías
Classes & Interfaces Versus

Nivel de acceso: predeterminado frente a protegido

La siguiente tabla muestra la diferencia entre el nivel de acceso predeterminado y protegido. Note la diferencia entre referencia y heredado.

Categorías
Classes & Interfaces

4 tipos de clases internas de Java

Hay 4 tipos diferentes de clases internas en Java. Esta publicación los ilustra usando 4 ejemplos simples.

1. Clases anidadas estáticas

class Outer {
	static class Inner {
		void go() {
			System.out.println("Inner class reference is: " + this);
		}
	}
}
 
public class Test {
	public static void main(String[] args) {
		Outer.Inner n = new Outer.Inner();
		n.go();
	}
}
Inner class reference is: [email protected]

2. Miembro de la clase interna

La clase de miembro es específica de la instancia. Tiene acceso a todos los métodos, campos y esta referencia externa.

public class Outer {
    private int x = 100;
 
    public void makeInner(){
        Inner in = new Inner();
        in.seeOuter();
    }
 
    class Inner{
        public void seeOuter(){
            System.out.println("Outer x is " + x);
            System.out.println("Inner class reference is " + this);
            System.out.println("Outer class reference is " + Outer.this);
        }
    }
 
    public static void main(String [] args){
    	Outer o = new Outer();
        Inner i = o.new Inner();
        i.seeOuter();
    }
}
Outer x is 100
Inner class reference is [email protected]
Outer class reference is [email protected]

3. Clases internas de método local

public class Outer {
	private String x = "outer";
 
	public void doStuff() {
		class MyInner {
			public void seeOuter() {
				System.out.println("x is " + x);
			}
		}
 
		MyInner i = new MyInner();
		i.seeOuter();
	}
 
	public static void main(String[] args) {
		Outer o = new Outer();
		o.doStuff();
	}
}
x is outer
public class Outer {
	private static String x = "static outer";
 
	public static void doStuff() {
		class MyInner {
			public void seeOuter() {
				System.out.println("x is " + x);
			}
		}
 
		MyInner i = new MyInner();
		i.seeOuter();
	}
 
	public static void main(String[] args) {
		Outer.doStuff();
	}
}
x is static outer

4. Clases internas anónimas

Esto se usa con frecuencia cuando agrega un escucha de acción a un widget en una aplicación GUI.

button.addActionListener(new ActionListener(){
     public void actionPerformed(ActionEvent e){
         comp.setText("Button has been clicked");
     }
});

Categorías
Classes & Interfaces

¿Qué es Instance Initializer en Java?

En esta publicación, ilustraré qué son el inicializador de variable de instancia, el inicializador de instancia, el inicializador estático y cómo funciona el inicializador de instancia en Java.

1. Orden de ejecución

Mira la siguiente clase, ¿sabes cuál se ejecuta primero?

public class Foo {
 
	//instance variable initializer
	String s = "abc";
 
	//constructor
	public Foo() {
		System.out.println("constructor called");
	}
 
	//static initializer
	static {
		System.out.println("static initializer called");
	}
 
	//instance initializer
	{
		System.out.println("instance initializer called");
	}
 
	public static void main(String[] args) {
		new Foo();
		new Foo();
	}
}

Producción:

static initializer called
instance initializer called
constructor called
instance initializer called
constructor called

2. ¿Cómo funciona el inicializador de instancias de Java?

El inicializador de instancia anterior contiene una declaración println. Para entender cómo funciona, podemos tratarlo como una declaración de asignación de variable, por ejemplo, b = 0. Esto puede hacer que sea más obvio de entender.

En vez de

int b = 0

, podemos escribirlo como

int b;
b = 0;

Por lo tanto, los inicializadores de instancia y los inicializadores de variable de instancia son prácticamente lo mismo.

3. ¿Cuándo son útiles los inicializadores de instancia?

El uso de inicializadores de instancia es poco común, pero aún puede ser una alternativa útil a los inicializadores de variables de instancia si:

(1) el código de inicializador debe manejar excepciones
(2) realice cálculos que no se pueden expresar con un inicializador de variable de instancia.

Por supuesto, dicho código podría escribirse en constructores. Pero si una clase tuviera varios constructores, tendría que repetir el código en cada constructor.

Con un inicializador de instancia, puede escribir el código una vez y se ejecutará sin importar qué constructor se use para crear el objeto. (Supongo que esto es solo un concepto y no se usa con frecuencia).

Otro caso en el que los inicializadores de instancia son útiles son las clases internas anónimas, que no pueden declarar ningún constructor en absoluto. (¿Será este un buen lugar para colocar una función de registro?)

Gracias a Heinrich Hartmann por su comentario:

También tenga en cuenta que las clases anónimas que implementan interfaces [1] no tienen constructores. Por lo tanto, los inicializadores de instancia son necesarios para ejecutar cualquier tipo de expresión en el momento de la construcción.

Referencia:
Inicialización de objetos en Java

Categorías
Classes & Interfaces

¿Cuándo usar constructores privados en Java?

Si un método es privado, significa que no se puede acceder a él desde ninguna clase que no sea él mismo. Este es el mecanismo de control de acceso proporcionado por Java. Cuando se usa apropiadamente, puede producir seguridad y funcionalidad. Los constructores, como los métodos regulares, también se pueden declarar como privados. Quizás se pregunte por qué necesitamos un constructor privado ya que solo es accesible desde su propia clase. Cuando una clase necesita evitar que la persona que llama cree objetos. Los constructores privados son adecuados. Los objetos solo se pueden construir internamente.

Una aplicación está en el patrón de diseño singleton. La política es que se supone que solo existe un objeto de esa clase. Entonces, ninguna otra clase que no sea ella misma puede acceder al constructor. Esto asegura la existencia de instancia única de la clase. Los constructores privados se han utilizado ampliamente en JDK, el siguiente código es parte de la clase Runtime.

public class Runtime {
	private static Runtime currentRuntime = new Runtime();
 
	public static Runtime getRuntime() {
		return currentRuntime;
	}
 
	// Don't let anyone else instantiate this class
	private Runtime() {
	}
}

Categorías
Classes & Interfaces

¿Cómo funciona la verificación de tipos estáticos en Java?

De Wiki:

La verificación de tipo estática es el proceso de verificar la seguridad del tipo de un programa basado en el análisis del código fuente de un programa.

La verificación de tipo dinámica es el proceso de verificar la seguridad del tipo de un programa en tiempo de ejecución

Java utiliza la verificación de tipos estáticos para analizar el programa durante la compilación para demostrar la ausencia de errores de tipo. La idea básica es nunca dejar que sucedan cosas malas en tiempo de ejecución. Al comprender el siguiente ejemplo, debe comprender bien cómo funciona la verificación de tipos estáticos en Java.

Ejemplo de código

Supongamos que tenemos las siguientes clases, A y B. B extiende A.

class A {
	A me() {
		return this;
	}
 
	public void doA() {
		System.out.println("Do A");
	}
}
 
class B extends A {
	public void doB() {
		System.out.println("Do B");
	}
}

En primer lugar, ¿qué devuelve «new B (). Me ()»? ¿Un objeto A o un objeto B?

Se declara que el método me () devuelve una A, por lo que durante el tiempo de compilación, el compilador solo ve que devuelve un objeto A. Sin embargo, en realidad devuelve un objeto B durante el tiempo de ejecución, ya que B hereda los métodos de A y lo devuelve (él mismo).

¿Cómo funciona la verificación de tipo estático?

La siguiente línea será ilegal, aunque el objeto que se invoca sea un objeto B. El problema es que su tipo de referencia es A. El compilador no conoce su tipo real durante el tiempo de compilación, por lo que ve el objeto como tipo A.

//illegal
new B().me().doB();

Por lo tanto, solo se puede invocar el siguiente método.

//legal
new B().me().doA();

Sin embargo, podemos convertir el objeto al tipo B, como el siguiente:

//legal
((B) new B().me()).doB();

Si se agrega la siguiente clase C,

class C extends A{
	public void doBad() {
		System.out.println("Do C");
	}
}

entonces la siguiente declaración es legal y puede pasar la verificación de tipo estático:

//legal
((C) new B().me()).beBad();

El compilador no sabe que es en tiempo real, pero el tiempo de ejecución lanzará una excepción de conversión ya que B no se puede convertir en C:

 java.lang.ClassCastException: B cannot be cast to C

Referencias:
1. Tipo de sistema

Categorías
Classes & Interfaces

¿Por qué no se puede anular el campo?

Este artículo muestra el concepto básico orientado a objetos en Java: Ocultación de campo.

1. ¿Se puede anular el campo en Java?

Primero echemos un vistazo al siguiente ejemplo que crea dos Sub objetos. Uno está asignado a una referencia secundaria y el otro a una referencia superior.

package oo;
 
class Super {
	String s = "Super";
}
 
class Sub extends Super {
	String s = "Sub";
}
 
public class FieldOverriding {
	public static void main(String[] args) {
		Sub c1 = new Sub();
		System.out.println(c1.s);
 
		Super c2 = new Sub();
		System.out.println(c2.s);
	}
}

¿Cuál es la salida?

Sub
Super

Creamos dos objetos Sub, pero ¿por qué el segundo imprime «Super»?

2. Ocultar campos en lugar de anularlos

En [1], hay una definición clara de campos de ocultación:

Dentro de una clase, un campo que tiene el mismo nombre que un campo en la superclase oculta el campo de la superclase, incluso si sus tipos son diferentes. Dentro de la subclase, el campo de la superclase no puede ser referenciado por su nombre simple. En cambio, se debe acceder al campo a través de super. En términos generales, no recomendamos ocultar campos ya que dificulta la lectura del código.

A partir de esta definición, los campos de miembros no se pueden anular como métodos. Cuando una subclase define un campo con el mismo nombre, la subclase simplemente declara un nuevo campo. El campo en la superclase es oculto. NO está anulado, por lo que no se puede acceder de forma polimórfica.

3. Formas de acceder a campos ocultos

1). Al utilizar el tipo de referencia de crianza, se puede acceder a los campos principales ocultos, como en el ejemplo anterior.
2). Al lanzar puedes acceder al miembro oculto en la superclase.

System.out.println(((Super)c1).s);

Referencias:
1. Ocultar campos

Categorías
Classes & Interfaces

¿Constructores de sub y súper clases en Java?

Esta publicación resume una pregunta común sobre los constructores de Java.

1. ¿Por qué la creación de un objeto de la subclase invoca también al constructor de la superclase?

class Super {
    String s;
 
    public Super(){
    	System.out.println("Super");
    }
}
 
public class Sub extends Super {
 
    public Sub(){
    	System.out.println("Sub");
    }
 
    public static void main(String[] args){
    	Sub s = new Sub();
    }
}

Imprime:

Super
Sub

Cuando se hereda de otra clase, primero se debe llamar a super () en el constructor. De lo contrario, el compilador insertará esa llamada. Esta es la razón por la que el superconstructor también se invoca cuando se crea un objeto Sub.

Esto no crea dos objetos, solo un objeto Sub. La razón para llamar al superconstructor es que si la superclase podría tener campos privados que deben ser inicializados por su constructor.

Después de que el compilador inserta el superconstructor, el constructor de la subclase tiene el siguiente aspecto:

    public Sub(){
    	super();
    	System.out.println("Sub");
    }

2. Un mensaje de error común: el superconstructor implícito no está definido para el constructor predeterminado

Este es un mensaje de error de compilación visto por muchos desarrolladores de Java:

«El superconstructor implícito no está definido para el constructor predeterminado. Debe definir un constructor explícito»

Este error de compilación se produce porque el superconstructor predeterminado no está definido. En Java, si una clase no define un constructor, el compilador insertará un constructor sin argumentos predeterminado para la clase por defecto. Si un constructor está definido en la clase Super, en este caso Super (String s), el compilador no insertará el constructor sin argumentos predeterminado. Esta es la situación de la clase Super anterior.

Los constructores de la clase Sub, ya sea con argumento o sin argumento, llamarán al superconstructor sin argumento. Dado que el compilador intenta insertar super () en los 2 constructores de la clase Sub, pero el constructor predeterminado de Super no está definido, el compilador informa el mensaje de error.

Para solucionar este problema, simplemente 1) agregue un constructor Super () a la clase Super como

public Super(){
    System.out.println("Super");
}

, o 2) eliminar el superconstructor autodefinido, o 3) agregar super(value) a los subconstructores.

3. Llamar explícitamente al superconstructor en el subconstructor

El siguiente código está bien:

subconstructor-con-parámetro

El subconstructor llama explícitamente al superconstructor con parámetro. El superconstructor está definido y es bueno invocarlo.

4. La regla

En resumen, las reglas son: el constructor de la subclase tiene que invocar al instructor de la superclase, ya sea explícitamente por el programador o implícitamente por el compilador. De cualquier manera, se debe definir el superconstructor invocado.

5. La pregunta interesante

¿Por qué Java no proporciona un constructor predeterminado, si la clase tiene un constructor con parámetro (s)?

Algunas respuestas: http://stackoverflow.com/q/16046200/127859

Categorías
Classes & Interfaces

¿Qué es la interfaz interna en Java?

¿Qué es la interfaz interna en Java?

La interfaz interna también se llama interfaz anidada, lo que significa declarar una interfaz dentro de otra interfaz. Por ejemplo, la interfaz de entrada se declara en la interfaz de mapa.

public interface Map {
	interface Entry{
		int getKey();
	}
 
	void clear();
}

¿Por qué utilizar la interfaz interna?

Hay varias razones convincentes para utilizar la interfaz interna:

  • Es una forma de agrupar lógicamente interfaces que solo se utilizan en un lugar.
  • Aumenta la encapsulación.
  • Las interfaces anidadas pueden conducir a un código más legible y fácil de mantener.

Un ejemplo de interfaz interna utilizada en la biblioteca estándar de Java es java.util.Map y Java.util.Map.Entry. Aquí java.util.Map también se usa como espacio de nombres. La entrada no pertenece al ámbito global, lo que significa que hay muchas otras entidades que son Entradas y no son entradas del Mapa necesarias. Esto indica que Entrada representa entradas relacionadas con el Mapa.

¿Cómo funciona la interfaz interna?

Para descubrir cómo funciona la interfaz interna, podemos compararla con clases anidadas. Las clases anidadas se pueden considerar como un método regular declarado en la clase externa. Dado que un método puede declararse como estático o no estático, las clases anidadas de forma similar pueden ser estáticas y no estáticas. La clase estática es como un método estático, solo puede acceder a los miembros de la clase externa a través de objetos. La clase no estática puede acceder a cualquier miembro de la clase externa.

Debido a que no se pueden crear instancias de una interfaz, la interfaz interna solo tiene sentido si es estática. Por lo tanto, por defecto, la inter interfaz es estática, no importa si agrega manualmente estática o no.

¿Un ejemplo simple de interfaz interna?

Map.java

public interface Map {
	interface Entry{
		int getKey();
	}
 
	void clear();
}

MapImpl.java

public class MapImpl implements Map {
 
 
	class ImplEntry implements Map.Entry{
		public int getKey() {
			return 0;
		}		
	}
 
	@Override
	public void clear() {
		//clear
	}
}